@flyos/design-system 3.13.0 → 3.16.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/fesm2022/flyos-design-system.mjs +3628 -2038
- package/fesm2022/flyos-design-system.mjs.map +1 -1
- package/package.json +1 -1
- package/scss/_fly-theme.scss +1 -1
- package/scss/_nova-motion.scss +1 -1
- package/scss/_nova-tokens.scss +1 -1
- package/scss/_nova-type.scss +1 -1
- package/types/flyos-design-system.d.ts +2177 -1461
- package/types/flyos-design-system.d.ts.map +1 -1
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import * as _angular_core from '@angular/core';
|
|
2
|
-
import { Type, InjectionToken, Signal, WritableSignal, OnInit, EventEmitter, OnChanges, OnDestroy, SimpleChanges, EnvironmentProviders, PipeTransform, signal, AfterViewInit, ElementRef, AfterViewChecked,
|
|
2
|
+
import { Type, InjectionToken, Signal, WritableSignal, OnInit, EventEmitter, OnChanges, OnDestroy, SimpleChanges, EnvironmentProviders, PipeTransform, signal, AfterViewInit, ElementRef, AfterViewChecked, Provider, ErrorHandler, TemplateRef } from '@angular/core';
|
|
3
3
|
import * as rxjs from 'rxjs';
|
|
4
4
|
import { Observable, MonoTypeOperatorFunction } from 'rxjs';
|
|
5
5
|
import { ControlValueAccessor, Validator, AbstractControl, ValidationErrors } from '@angular/forms';
|
|
@@ -122,7 +122,7 @@ interface LaunchContext {
|
|
|
122
122
|
* provisioning. Remotes subscribe to deep links via the federation-safe surfaces
|
|
123
123
|
* instead: `FLYOS_LAUNCH_EVENT` (window CustomEvent) plus the
|
|
124
124
|
* `__FLYOS_PENDING_LAUNCHES__` registry on `globalThis`. See
|
|
125
|
-
* <c>skills/
|
|
125
|
+
* <c>skills/platform-deep-linking.md</c>.
|
|
126
126
|
*/
|
|
127
127
|
declare const LAUNCH_CONTEXT: InjectionToken<Signal<LaunchContext | null>>;
|
|
128
128
|
/**
|
|
@@ -168,7 +168,7 @@ type FlyosPendingLaunches = Record<string, LaunchContext>;
|
|
|
168
168
|
*
|
|
169
169
|
* Only the shell may act on this: it owns the app registry and the window manager,
|
|
170
170
|
* neither of which is reachable from a federated remote. See
|
|
171
|
-
* `skills/
|
|
171
|
+
* `skills/platform-deep-linking.md` § "Initiator side (federated remote)".
|
|
172
172
|
*/
|
|
173
173
|
interface FlyLaunchRequestDetail {
|
|
174
174
|
/** Shell-registry app id of the app to open, e.g. `'chats'`. */
|
|
@@ -2377,7 +2377,7 @@ declare class FlyRemoteRouter {
|
|
|
2377
2377
|
* `/trends/abc`) instead would leave a host-unroutable path in the bar — on
|
|
2378
2378
|
* reload the shell router falls through to its `**` wildcard, redirects to
|
|
2379
2379
|
* `/desktop`, and the deep link is silently lost. See
|
|
2380
|
-
* skills/
|
|
2380
|
+
* skills/platform-deep-linking.md.
|
|
2381
2381
|
*
|
|
2382
2382
|
* `flyRemoteUrl` is still stashed in the history state so the popstate
|
|
2383
2383
|
* listener restores the exact remote URL for back/forward without re-parsing
|
|
@@ -2467,6 +2467,21 @@ interface ConnectRemoteLaunchOptions {
|
|
|
2467
2467
|
* `route => void flyRouter.navigateByUrl(route)`.
|
|
2468
2468
|
*/
|
|
2469
2469
|
readonly navigate: (route: string) => void;
|
|
2470
|
+
/**
|
|
2471
|
+
* Optional side-channel for the rest of the launch — most importantly `ctx.params`,
|
|
2472
|
+
* which {@link navigate} cannot carry (it is handed a route string).
|
|
2473
|
+
*
|
|
2474
|
+
* Called once per accepted (version-deduped) launch, BEFORE {@link navigate}, and
|
|
2475
|
+
* called even when `ctx.route` is `null` — a params-only launch ("re-filter what is
|
|
2476
|
+
* already open") is a real case and must not be swallowed by the null-route
|
|
2477
|
+
* navigation no-op.
|
|
2478
|
+
*
|
|
2479
|
+
* Prefer {@link FlyLaunchContextService} over this callback for anything that isn't
|
|
2480
|
+
* the root component: the helper publishes every accepted launch there too, so a
|
|
2481
|
+
* lazily-mounted leaf can `inject(FlyLaunchContextService).contextFor(appId)` without
|
|
2482
|
+
* the root having to thread a value down. This hook is for root-local reactions.
|
|
2483
|
+
*/
|
|
2484
|
+
readonly onLaunch?: (ctx: LaunchContext) => void;
|
|
2470
2485
|
/**
|
|
2471
2486
|
* Gate. Pass your `isEmbedded` flag — when `false` the helper is a no-op (a
|
|
2472
2487
|
* standalone remote has no shell dispatcher). Defaults to `true`. The helper is
|
|
@@ -2479,7 +2494,7 @@ interface ConnectRemoteLaunchOptions {
|
|
|
2479
2494
|
* Federation-safe deep-link RECEIVER for an Angular Native-Federation remote — the
|
|
2480
2495
|
* remote-side counterpart of the shell's `connectWindowRoute`. Collapses the
|
|
2481
2496
|
* drain + dedupe + listen + cleanup boilerplate every remote root used to
|
|
2482
|
-
* hand-roll (see `skills/
|
|
2497
|
+
* hand-roll (see `skills/platform-deep-linking.md` § "Receiver side") into one
|
|
2483
2498
|
* call, so the correct contract can't be hand-rolled wrong.
|
|
2484
2499
|
*
|
|
2485
2500
|
* **Must be called from an injection context** (component constructor or a field
|
|
@@ -2502,12 +2517,32 @@ interface ConnectRemoteLaunchOptions {
|
|
|
2502
2517
|
* `appId`: the {@link FLYOS_LAUNCH_EVENT} window `CustomEvent` and the
|
|
2503
2518
|
* `globalThis[FlyosPendingLaunchesGlobalKey]` registry. This helper consumes both.
|
|
2504
2519
|
*
|
|
2520
|
+
* ## The launch PARAMS
|
|
2521
|
+
* `navigate` receives a route string, so it structurally cannot carry `ctx.params` —
|
|
2522
|
+
* the payload dashboard drill-down rides on (`skills/dashboard-reports.md` §
|
|
2523
|
+
* "Drill-down" sends `{ [filterParam]: clickedValue }`). Before DS 3.15.0 this helper
|
|
2524
|
+
* read `ctx.route` and dropped the rest, so every drill-down into a federated remote
|
|
2525
|
+
* opened an UNFILTERED register, and consumers hand-rolled a second, non-destructive
|
|
2526
|
+
* peek at the same pending-launch registry — with a load-bearing construction-ordering
|
|
2527
|
+
* dependency on running before this helper's drain deleted the entry.
|
|
2528
|
+
*
|
|
2529
|
+
* Every accepted launch is now published to {@link FlyLaunchContextService}, keyed by
|
|
2530
|
+
* `appId`, so any component in the remote reads the full context — params included —
|
|
2531
|
+
* with no ordering constraint:
|
|
2532
|
+
*
|
|
2533
|
+
* ```ts
|
|
2534
|
+
* private readonly ctx = inject(FlyLaunchContextService).contextFor('ppm');
|
|
2535
|
+
* ```
|
|
2536
|
+
*
|
|
2537
|
+
* {@link ConnectRemoteLaunchOptions.onLaunch} is the callback form, for a root-local
|
|
2538
|
+
* reaction that needs no injectable.
|
|
2539
|
+
*
|
|
2505
2540
|
* ## Two inbound paths, one dedupe
|
|
2506
2541
|
* 1. **First-mount drain.** The launch event fires BEFORE this listener attaches
|
|
2507
2542
|
* for the very first launch, so the shell stashes the latest context per
|
|
2508
2543
|
* `appId` on the `globalThis` registry. The helper reads it then **deletes**
|
|
2509
2544
|
* it — never leaving a stale entry behind (a leftover entry would re-apply on
|
|
2510
|
-
* every re-mount; this is the failure mode `skills/
|
|
2545
|
+
* every re-mount; this is the failure mode `skills/platform-deep-linking.md`
|
|
2511
2546
|
* § "What NOT to do" warns about).
|
|
2512
2547
|
* 2. **Live event.** Re-launches into an already-mounted remote arrive on
|
|
2513
2548
|
* {@link FLYOS_LAUNCH_EVENT}; the `appId` filter is mandatory.
|
|
@@ -2528,6 +2563,111 @@ interface ConnectRemoteLaunchOptions {
|
|
|
2528
2563
|
*/
|
|
2529
2564
|
declare function connectRemoteLaunch(opts: ConnectRemoteLaunchOptions): void;
|
|
2530
2565
|
|
|
2566
|
+
/**
|
|
2567
|
+
* Shared cross-bundle store key + sync event for the inbound launch channel.
|
|
2568
|
+
*
|
|
2569
|
+
* **Public contract**, for the same reason {@link FLY_REMOTE_CONTEXT_STORE_KEY} is: a
|
|
2570
|
+
* consumer pinned to a DS older than 3.15.0 can read this slot directly (same shape,
|
|
2571
|
+
* keyed by appId) rather than re-deriving the peek-the-pending-registry workaround.
|
|
2572
|
+
* Keep these literals stable; they are an integration boundary.
|
|
2573
|
+
*/
|
|
2574
|
+
declare const FLY_LAUNCH_CONTEXT_STORE_KEY = "__flyLaunchContext__";
|
|
2575
|
+
declare const FLY_LAUNCH_CONTEXT_EVENT = "fly:launch-context";
|
|
2576
|
+
/**
|
|
2577
|
+
* Shell → remote launch channel: the **whole** {@link LaunchContext} of the most
|
|
2578
|
+
* recent launch into each app, `params` included.
|
|
2579
|
+
*
|
|
2580
|
+
* Why this exists
|
|
2581
|
+
* ---------------
|
|
2582
|
+
* {@link connectRemoteLaunch} consumes the two DI-free launch surfaces
|
|
2583
|
+
* (`FLYOS_LAUNCH_EVENT` + the `__FLYOS_PENDING_LAUNCHES__` registry) and applies the
|
|
2584
|
+
* `route` half by navigating. Until DS 3.15.0 it read `ctx.route` and **nothing else**,
|
|
2585
|
+
* so `ctx.params` — the payload dashboard drill-down carries (`skills/dashboard-reports.md`
|
|
2586
|
+
* § "Drill-down": `{ [filterParam]: clickedValue }`) — was silently dropped, and every
|
|
2587
|
+
* drill-down into a federated remote landed on an UNFILTERED register.
|
|
2588
|
+
*
|
|
2589
|
+
* The shell-side answer to "read the launch params" is `inject(LAUNCH_CONTEXT)`, which a
|
|
2590
|
+
* federated remote must not use: Native Federation can split that `InjectionToken`
|
|
2591
|
+
* instance across host and remote bundles, so `inject()` returns `null` (see
|
|
2592
|
+
* `LAUNCH_CONTEXT`'s own doc). This service is the federation-safe counterpart —
|
|
2593
|
+
* `connectRemoteLaunch` publishes here, and any component in the remote (however deep, in
|
|
2594
|
+
* whatever lazy chunk) injects this and reads the same context.
|
|
2595
|
+
*
|
|
2596
|
+
* Why `globalThis`, not just the DI singleton
|
|
2597
|
+
* -------------------------------------------
|
|
2598
|
+
* Identical rationale to {@link FlyRemoteContextService}: the shell builds the design
|
|
2599
|
+
* system from workspace SOURCE while remotes consume the published npm package, and NF's
|
|
2600
|
+
* version negotiation has silently split `providedIn: 'root'` before. State therefore
|
|
2601
|
+
* lives on `globalThis` (see {@link FLY_LAUNCH_CONTEXT_STORE_KEY}); {@link context} /
|
|
2602
|
+
* {@link params} read it directly (split-proof, synchronous) and a per-instance signal
|
|
2603
|
+
* mirrors it for reactive consumers, re-synced from a `globalThis` event whenever another
|
|
2604
|
+
* copy of the service mutates the store.
|
|
2605
|
+
*
|
|
2606
|
+
* Reading it
|
|
2607
|
+
* ----------
|
|
2608
|
+
* ```ts
|
|
2609
|
+
* private readonly launch = inject(FlyLaunchContextService);
|
|
2610
|
+
* private readonly drillDown = this.launch.contextFor('ppm');
|
|
2611
|
+
* private lastVersion = -1; // -1 never collides: the shell counts from 1
|
|
2612
|
+
*
|
|
2613
|
+
* constructor() {
|
|
2614
|
+
* effect(() => {
|
|
2615
|
+
* const ctx = this.drillDown();
|
|
2616
|
+
* if (!ctx || ctx.version === this.lastVersion) return; // version-dedupe is the consumer's job
|
|
2617
|
+
* this.lastVersion = ctx.version;
|
|
2618
|
+
* const status = ctx.params?.['status'];
|
|
2619
|
+
* if (typeof status === 'string') this.applyStatusFilter(status);
|
|
2620
|
+
* });
|
|
2621
|
+
* }
|
|
2622
|
+
* ```
|
|
2623
|
+
*
|
|
2624
|
+
* Staleness
|
|
2625
|
+
* ---------
|
|
2626
|
+
* An entry is **not** dropped once read — a lazily-mounted consumer must still find the
|
|
2627
|
+
* launch that opened the window, which may have arrived long before its chunk loaded (the
|
|
2628
|
+
* exact ordering hazard the hand-rolled "peek the pending registry before
|
|
2629
|
+
* `connectRemoteLaunch` drains it" workaround existed to dodge). It cannot go stale across
|
|
2630
|
+
* a remount for the same reason `connectRemoteLaunch`'s `lastVersion` reset is safe: the
|
|
2631
|
+
* shell is the single writer and `reloadWindowContent` ALWAYS re-publishes the window's
|
|
2632
|
+
* CURRENT context (`params: null`, bumped version) before dropping the injector, so the
|
|
2633
|
+
* remount's drain overwrites this slot before any consumer mounts. Consumers dedupe on
|
|
2634
|
+
* `version` regardless, exactly as they must for the live-event path.
|
|
2635
|
+
*
|
|
2636
|
+
* Keyed by `appId` (last launch wins) — a single live window per app, matching
|
|
2637
|
+
* `__FLYOS_PENDING_LAUNCHES__`'s own keying.
|
|
2638
|
+
*/
|
|
2639
|
+
declare class FlyLaunchContextService {
|
|
2640
|
+
private readonly _byApp;
|
|
2641
|
+
/** Every app's latest inbound launch context, keyed by app id. Reactive. */
|
|
2642
|
+
readonly contexts: Signal<ReadonlyMap<string, LaunchContext>>;
|
|
2643
|
+
/**
|
|
2644
|
+
* `contextFor` memo — one computed per app id, so repeated calls (a component field
|
|
2645
|
+
* initializer re-running per instance) hand back the SAME signal instead of leaking a
|
|
2646
|
+
* new computed each time.
|
|
2647
|
+
*/
|
|
2648
|
+
private readonly perApp;
|
|
2649
|
+
constructor();
|
|
2650
|
+
/**
|
|
2651
|
+
* Record an inbound launch for an app. Called by {@link connectRemoteLaunch} once per
|
|
2652
|
+
* accepted (version-deduped) launch — a remote should not normally call this itself.
|
|
2653
|
+
*/
|
|
2654
|
+
publish(appId: string, ctx: LaunchContext): void;
|
|
2655
|
+
/** Latest launch context for an app as a signal — the reactive read path. */
|
|
2656
|
+
contextFor(appId: string): Signal<LaunchContext | null>;
|
|
2657
|
+
/** Latest launch context for an app, read straight off the store. `null` when none. */
|
|
2658
|
+
context(appId: string): LaunchContext | null;
|
|
2659
|
+
/**
|
|
2660
|
+
* The `params` half of an app's latest launch — the drill-down payload. `null` when the
|
|
2661
|
+
* app has no launch context, or when the launch carried no params. The **consumer**
|
|
2662
|
+
* interprets the keys against its own filter contract; the platform never does.
|
|
2663
|
+
*/
|
|
2664
|
+
params(appId: string): Readonly<Record<string, unknown>> | null;
|
|
2665
|
+
/** Drop an app's launch context. No-op if absent. Mainly for teardown and tests. */
|
|
2666
|
+
clear(appId: string): void;
|
|
2667
|
+
static ɵfac: _angular_core.ɵɵFactoryDeclaration<FlyLaunchContextService, never>;
|
|
2668
|
+
static ɵprov: _angular_core.ɵɵInjectableDeclaration<FlyLaunchContextService>;
|
|
2669
|
+
}
|
|
2670
|
+
|
|
2531
2671
|
/**
|
|
2532
2672
|
* A federated remote's current navigation context, as published to the shell.
|
|
2533
2673
|
*
|
|
@@ -3903,7 +4043,7 @@ interface AgentDragPayload<T = unknown> {
|
|
|
3903
4043
|
* DS package is shell-agnostic and shouldn't grow a second copy of the
|
|
3904
4044
|
* URL grammar. Apps building envelopes are expected to stamp routes that
|
|
3905
4045
|
* match their own internal route schema (e.g. dashboard publishes
|
|
3906
|
-
* `/reports/{id}` and `/custom/{id}`); see `skills/
|
|
4046
|
+
* `/reports/{id}` and `/custom/{id}`); see `skills/platform-deep-linking.md`.
|
|
3907
4047
|
*
|
|
3908
4048
|
* Backwards-compat: absent on v1 payloads and on v2 payloads built
|
|
3909
4049
|
* before this field was added. Persisted JSONB chips without the field
|
|
@@ -5983,7 +6123,7 @@ interface FlySelectPanelPosition {
|
|
|
5983
6123
|
* input still wins. It used to default to a hardcoded English literal that every consumer had to
|
|
5984
6124
|
* remember to override — none did, so a searchable select read "Search…" under ar/fr/ur.
|
|
5985
6125
|
* Styling composes the Nova token language (`--w*` ramp, `--accent`, `nova-glass.popover`) — see
|
|
5986
|
-
* `skills/
|
|
6126
|
+
* `skills/shell-design-language.md` §3.2 and `.workflow/plans/ux-refresh/notes/S1.7-form-family.md`.
|
|
5987
6127
|
*
|
|
5988
6128
|
* **Positioning (S1.7 — Nova):** the panel is `position: fixed`, measured from the trigger, and
|
|
5989
6129
|
* **portaled to `<body>`** the same way {@link ContextMenuComponent} escapes a clipping/glass
|
|
@@ -6514,6 +6654,21 @@ interface GanttRow {
|
|
|
6514
6654
|
* expanding it emits {@link FlyGanttComponent.rowExpand} instead of revealing nothing.
|
|
6515
6655
|
*/
|
|
6516
6656
|
hasChildren?: boolean;
|
|
6657
|
+
/**
|
|
6658
|
+
* Whether a row that currently has NO children is still a valid drag-to-reorder PARENT —
|
|
6659
|
+
* dropping another row directly beneath it files that row as its first child instead of as its
|
|
6660
|
+
* sibling. Independent of {@link hasChildren}: that field also paints a chevron, which is wrong
|
|
6661
|
+
* for a container with nothing in it yet (a milestone that has no tasks is a point-in-time
|
|
6662
|
+
* marker, not an expandable list with zero items). This field changes ONLY what
|
|
6663
|
+
* `resolveGanttReorderDrop` does with a drop on this row; it paints nothing.
|
|
6664
|
+
*
|
|
6665
|
+
* Existing rows with real children need no help — `hasChildren && !collapsed` already nests
|
|
6666
|
+
* into them. This exists for the row that CAN adopt a child but has not yet: the indent action
|
|
6667
|
+
* already reaches this case (`canIndentGanttRow` only checks depth, never child count), so
|
|
6668
|
+
* without this flag a drag and an indent onto the same empty container disagreed — one nested
|
|
6669
|
+
* the row, the other filed it as a root/backlog sibling with no explanation.
|
|
6670
|
+
*/
|
|
6671
|
+
canAdoptChildren?: boolean;
|
|
6517
6672
|
/**
|
|
6518
6673
|
* Optional baseline (plan-of-record) date, ISO `YYYY-MM-DD`. When both `baselineStart` and
|
|
6519
6674
|
* `baselineEnd` are set and {@link FlyGanttComponent.showBaselines} is on, the chart renders a
|
|
@@ -6569,6 +6724,43 @@ interface GanttDependencyCreate {
|
|
|
6569
6724
|
toId: string;
|
|
6570
6725
|
type: GanttDependencyType;
|
|
6571
6726
|
}
|
|
6727
|
+
/**
|
|
6728
|
+
* Payload of {@link FlyGanttComponent.rowReorder} — a label row dragged to a new place in the tree.
|
|
6729
|
+
*
|
|
6730
|
+
* Carries the FULL new sibling order rather than a `before`/`after` hint, because that is the shape
|
|
6731
|
+
* every ordering endpoint actually takes (an ordered, complete id set) and because re-deriving it
|
|
6732
|
+
* consumer-side is where the chart's order and the consumer's start to disagree. `parentId` is the
|
|
6733
|
+
* parent AFTER the move — `null` for a root row — so a drop that also re-homes the row (dragging a
|
|
6734
|
+
* task from one summary group into another) is one event, not two.
|
|
6735
|
+
*
|
|
6736
|
+
* The chart does NOT judge whether a level change is legal: only the consumer knows whether its
|
|
6737
|
+
* two outline levels are the same kind of thing. Reject the move by simply not persisting it; the
|
|
6738
|
+
* rows are re-rendered from the consumer's own input either way, so nothing is left inconsistent.
|
|
6739
|
+
*/
|
|
6740
|
+
interface GanttRowReorder {
|
|
6741
|
+
/** The row that moved. */
|
|
6742
|
+
readonly id: string;
|
|
6743
|
+
/** Its parent after the move; `null` = a root row. */
|
|
6744
|
+
readonly parentId: string | null;
|
|
6745
|
+
/** Zero-based slot among `parentId`'s children after the move. */
|
|
6746
|
+
readonly index: number;
|
|
6747
|
+
/** Every child of `parentId` after the move, in their new order (includes {@link id}). */
|
|
6748
|
+
readonly siblingIds: readonly string[];
|
|
6749
|
+
}
|
|
6750
|
+
/**
|
|
6751
|
+
* Payload of {@link FlyGanttComponent.rowIndentChange} — the outline-level nudge behind an
|
|
6752
|
+
* indent / outdent action.
|
|
6753
|
+
*
|
|
6754
|
+
* `delta` is `+1` (indent — become a child of the row above) or `-1` (outdent — become a sibling of
|
|
6755
|
+
* the current parent). `parentId` is the resulting parent, resolved by the chart from the row's
|
|
6756
|
+
* neighbours so every consumer does not re-implement "which row would adopt it": `null` means the
|
|
6757
|
+
* row lands at the root.
|
|
6758
|
+
*/
|
|
6759
|
+
interface GanttRowIndentChange {
|
|
6760
|
+
readonly id: string;
|
|
6761
|
+
readonly delta: 1 | -1;
|
|
6762
|
+
readonly parentId: string | null;
|
|
6763
|
+
}
|
|
6572
6764
|
/** Payload of {@link FlyGanttComponent.dependencyDelete} — the edge the user removed. */
|
|
6573
6765
|
interface GanttDependencyDelete {
|
|
6574
6766
|
fromId: string;
|
|
@@ -6605,6 +6797,10 @@ interface GanttFlatRow {
|
|
|
6605
6797
|
hasChildren: boolean;
|
|
6606
6798
|
collapsed: boolean;
|
|
6607
6799
|
}
|
|
6800
|
+
interface ResolvedDates {
|
|
6801
|
+
start: Date | null;
|
|
6802
|
+
end: Date | null;
|
|
6803
|
+
}
|
|
6608
6804
|
/** Render shape a row resolves to — decides which geometry fields on its VM are meaningful. */
|
|
6609
6805
|
type RowShape = 'bar' | 'milestone' | 'group' | 'empty';
|
|
6610
6806
|
/** Which end of a bar a link gesture grabbed / was dropped on. */
|
|
@@ -6650,7 +6846,7 @@ interface GanttLinkGesture {
|
|
|
6650
6846
|
* `gantt-label-pane.ts`: a few pure functions plus one signal-based class composed by the host).
|
|
6651
6847
|
* The functions below remain dependency-free — no Angular, no DOM — for the same reason
|
|
6652
6848
|
* `gantt-scale.ts`'s are: jsdom lays nothing out, so pure functions are the only directly
|
|
6653
|
-
* testable form of this math (skill:
|
|
6849
|
+
* testable form of this math (skill: ds-gantt.md §8).
|
|
6654
6850
|
*
|
|
6655
6851
|
* ## The `viewBox`-pan trick this math drives
|
|
6656
6852
|
* The body `<svg>` stays `position: absolute`, sized to only the rendered window
|
|
@@ -6718,17 +6914,120 @@ interface GanttRowVm {
|
|
|
6718
6914
|
/** Baseline overlay geometry, or `null` when the row has none (or baselines are hidden). */
|
|
6719
6915
|
baseline: GanttBaselineVm | null;
|
|
6720
6916
|
}
|
|
6721
|
-
|
|
6917
|
+
/**
|
|
6918
|
+
* What the geometry needs from its host, as signals rather than a component reference — the same
|
|
6919
|
+
* one-way shape {@link GanttLabelPane} and {@link GanttLinkGestures} take.
|
|
6920
|
+
*/
|
|
6921
|
+
interface GanttRowGeometryDeps {
|
|
6922
|
+
readonly rowHeight: Signal<number>;
|
|
6923
|
+
readonly rtl: Signal<boolean>;
|
|
6924
|
+
readonly domain: Signal<GanttDomain>;
|
|
6925
|
+
readonly pxPerDay: Signal<number>;
|
|
6926
|
+
readonly innerWidth: Signal<number>;
|
|
6927
|
+
readonly showBaselines: Signal<boolean>;
|
|
6928
|
+
readonly readonly: Signal<boolean>;
|
|
6929
|
+
/** Every row's effective `{start,end}` (`resolveRowDates`), including derived group spans. */
|
|
6930
|
+
readonly resolvedDates: Signal<ReadonlyMap<string, ResolvedDates>>;
|
|
6931
|
+
/** The in-flight bar drag, folded into the geometry so the bar follows the pointer. */
|
|
6932
|
+
readonly dragPreview: Signal<{
|
|
6933
|
+
id: string;
|
|
6934
|
+
start: Date;
|
|
6935
|
+
end: Date;
|
|
6936
|
+
} | null>;
|
|
6937
|
+
/** The row-band tint, already faded to its low alpha (or `null`). */
|
|
6938
|
+
readonly tintFor: (row: GanttRow) => string | null;
|
|
6939
|
+
/** The localized accessible label for a row. */
|
|
6940
|
+
readonly ariaFor: (row: GanttRow, start: Date | null, end: Date | null, shape: RowShape) => string;
|
|
6941
|
+
}
|
|
6942
|
+
/**
|
|
6943
|
+
* Render-space geometry for a Gantt row: the view-model one flattened row resolves to, and every
|
|
6944
|
+
* shape derived from it.
|
|
6945
|
+
*
|
|
6946
|
+
* ## Why this is not in the component
|
|
6947
|
+
* `fly-gantt` composes its gestures out of one-concern classes already ({@link GanttLabelPane},
|
|
6948
|
+
* {@link GanttLinkGestures}, {@link GanttViewport}, {@link GanttPan}) and this is the matching
|
|
6949
|
+
* carve on the RENDER side: everything here is "given a row and the current scale, where is it and
|
|
6950
|
+
* what shape is it", with no knowledge of selection, collapse, windowing, events or i18n beyond the
|
|
6951
|
+
* one label callback. Keeping it here means the component's remaining bulk is state and wiring, and
|
|
6952
|
+
* the geometry — the part that is actually hard to read — sits beside the scale math it calls.
|
|
6953
|
+
*
|
|
6954
|
+
* ## RTL
|
|
6955
|
+
* Nothing here branches on direction except through `mapX`/`projectBar` and the two `sign` terms
|
|
6956
|
+
* below, because the whole coordinate space is pre-mirrored (see `gantt-scale.ts`). The
|
|
6957
|
+
* consequence worth remembering: under RTL a row's `startX` is GREATER than its `endX`.
|
|
6958
|
+
*/
|
|
6959
|
+
declare class GanttRowGeometry {
|
|
6960
|
+
private readonly deps;
|
|
6961
|
+
constructor(deps: GanttRowGeometryDeps);
|
|
6962
|
+
/** Bar height for the current row height — the band minus its vertical padding. */
|
|
6963
|
+
readonly barHeight: Signal<number>;
|
|
6964
|
+
/** Full geometry for one row — used for rendered rows AND for link endpoints outside the window. */
|
|
6965
|
+
forFlat(flat: GanttFlatRow, index: number): GanttRowVm;
|
|
6966
|
+
barTop(vm: GanttRowVm): number;
|
|
6967
|
+
/** Baseline underbar's top edge — a thin strip directly beneath the main bar. */
|
|
6968
|
+
baselineBarTop(vm: GanttRowVm): number;
|
|
6969
|
+
private milestoneR;
|
|
6970
|
+
/** Diamond polygon points for a milestone marker. */
|
|
6971
|
+
diamondPoints(vm: GanttRowVm): string;
|
|
6972
|
+
/** Hollow outline diamond for a milestone row's baseline date (its own x, same row's y). */
|
|
6973
|
+
baselineDiamondPoints(vm: GanttRowVm): string;
|
|
6974
|
+
/**
|
|
6975
|
+
* Link connector x for a milestone. A diamond has no width, so the connector is nudged clear
|
|
6976
|
+
* of the marker in the forward-in-time direction (which flips under RTL).
|
|
6977
|
+
*/
|
|
6978
|
+
milestoneConnectorX(vm: GanttRowVm): number;
|
|
6979
|
+
/**
|
|
6980
|
+
* Connector x for one END of a bar, pushed into the gutter BESIDE the bar rather than sitting on
|
|
6981
|
+
* its edge (see {@link CONNECTOR_GAP}). Forward-in-time is `+x` LTR and `-x` RTL, so the start
|
|
6982
|
+
* connector always lands before the bar and the finish connector after it, in reading order.
|
|
6983
|
+
*/
|
|
6984
|
+
connectorX(vm: GanttRowVm, anchor: 'start' | 'finish'): number;
|
|
6985
|
+
/** Summary-bracket path (thin bar + down-turned end caps) for a group row. */
|
|
6986
|
+
groupPath(vm: GanttRowVm): string;
|
|
6987
|
+
/** Inline-start label indent for a tree depth. */
|
|
6988
|
+
indentFor(depth: number): number;
|
|
6989
|
+
}
|
|
6990
|
+
|
|
6991
|
+
/** Which part of a bar the press grabbed. */
|
|
6992
|
+
type GanttBarDragMode = 'move' | 'resize-start' | 'resize-end';
|
|
6993
|
+
/** The follow-the-cursor date readout shown while a drag runs. */
|
|
6994
|
+
interface GanttDragTooltip {
|
|
6995
|
+
readonly x: number;
|
|
6996
|
+
readonly y: number;
|
|
6997
|
+
readonly text: string;
|
|
6998
|
+
}
|
|
6999
|
+
|
|
7000
|
+
/**
|
|
7001
|
+
* Which end of each row a relationship touches.
|
|
7002
|
+
*
|
|
7003
|
+
* The two letters ARE the anchors — `FS` is "from my **F**inish to your **S**tart" — so this is
|
|
7004
|
+
* the exact inverse of `linkTypeFor`, and stating it as a function rather than re-reading the
|
|
7005
|
+
* letters at each call site is what keeps the arrowhead, the re-target handle and the type
|
|
7006
|
+
* derivation from ever disagreeing about which end an arrow lands on.
|
|
7007
|
+
*/
|
|
7008
|
+
declare function linkAnchorsFor(type: GanttDependencyType): {
|
|
7009
|
+
from: GanttLinkAnchor;
|
|
7010
|
+
to: GanttLinkAnchor;
|
|
7011
|
+
};
|
|
7012
|
+
/** A dependency arrow, ready to draw. Render space throughout. */
|
|
7013
|
+
interface GanttLinkVm {
|
|
6722
7014
|
key: string;
|
|
6723
7015
|
fromId: string;
|
|
6724
7016
|
toId: string;
|
|
6725
7017
|
type: GanttDependencyType;
|
|
6726
7018
|
path: string;
|
|
6727
|
-
/** Anchor for the delete affordance shown while the link is selected
|
|
7019
|
+
/** Anchor for the delete affordance shown while the link is selected. */
|
|
6728
7020
|
badgeX: number;
|
|
6729
7021
|
badgeY: number;
|
|
7022
|
+
/** The arrowhead end — where the re-target handle sits while the link is selected. */
|
|
7023
|
+
headX: number;
|
|
7024
|
+
headY: number;
|
|
7025
|
+
/** The end of the SOURCE row this arrow leaves from, which a re-target drag has to start on. */
|
|
7026
|
+
fromAnchor: GanttLinkAnchor;
|
|
6730
7027
|
ariaLabel: string;
|
|
6731
7028
|
}
|
|
7029
|
+
|
|
7030
|
+
/** One dependency arrow, routed and ready for the template. */
|
|
6732
7031
|
/**
|
|
6733
7032
|
* **`fly-gantt`** — the design-system SVG Gantt chart.
|
|
6734
7033
|
*
|
|
@@ -6762,9 +7061,21 @@ interface LinkVm {
|
|
|
6762
7061
|
declare class FlyGanttComponent {
|
|
6763
7062
|
readonly i18n: I18nService;
|
|
6764
7063
|
private readonly destroyRef;
|
|
7064
|
+
/**
|
|
7065
|
+
* App-level presentation defaults, when the consuming app provided any. Optional by
|
|
7066
|
+
* construction: a chart with no provider behaves exactly as it did before the token existed.
|
|
7067
|
+
*/
|
|
7068
|
+
private readonly appDefaults;
|
|
6765
7069
|
readonly rows: _angular_core.InputSignal<readonly GanttRow[]>;
|
|
6766
7070
|
readonly dependencies: _angular_core.InputSignal<readonly GanttDependency[]>;
|
|
6767
|
-
|
|
7071
|
+
/**
|
|
7072
|
+
* Time-grid resolution. `null` defers to {@link FlyGanttDefaults.zoom}, then to `'week'`.
|
|
7073
|
+
*
|
|
7074
|
+
* Widened from `GanttZoom` to `GanttZoom | null` so the same three-step precedence
|
|
7075
|
+
* (input → app default → built-in) applies to every presentation input. Passing a concrete zoom
|
|
7076
|
+
* is unchanged.
|
|
7077
|
+
*/
|
|
7078
|
+
readonly zoom: _angular_core.InputSignal<GanttZoom | null>;
|
|
6768
7079
|
/** Draw the vertical "today" marker when today falls inside the domain. */
|
|
6769
7080
|
readonly showToday: _angular_core.InputSignal<boolean>;
|
|
6770
7081
|
/** Globally disable drag/resize/link (individual rows can also be `readonly`). */
|
|
@@ -6774,11 +7085,11 @@ declare class FlyGanttComponent {
|
|
|
6774
7085
|
* divider from there; once they have, this input only re-seeds the pane if
|
|
6775
7086
|
* {@link resetLabelWidth} is called (double-clicking the divider does exactly that).
|
|
6776
7087
|
*/
|
|
6777
|
-
readonly labelWidth: _angular_core.InputSignal<number>;
|
|
7088
|
+
readonly labelWidth: _angular_core.InputSignal<number | null>;
|
|
6778
7089
|
/** Let the user drag the divider between the label pane and the time grid. */
|
|
6779
7090
|
readonly resizableLabels: _angular_core.InputSignal<boolean>;
|
|
6780
|
-
/** Row band height in px. */
|
|
6781
|
-
readonly rowHeight: _angular_core.InputSignal<number>;
|
|
7091
|
+
/** Row band height in px. `null` defers to {@link FlyGanttDefaults.rowHeight}, then to `34`. */
|
|
7092
|
+
readonly rowHeight: _angular_core.InputSignal<number | null>;
|
|
6782
7093
|
/** Hard cap on the flattened row list; beyond it the list is truncated (see class doc).
|
|
6783
7094
|
* `0` (the default) is uncapped — windowing (below) is what keeps an uncapped chart cheap. */
|
|
6784
7095
|
readonly maxRows: _angular_core.InputSignal<number>;
|
|
@@ -6793,6 +7104,31 @@ declare class FlyGanttComponent {
|
|
|
6793
7104
|
readonly virtualized: _angular_core.InputSignal<boolean>;
|
|
6794
7105
|
/** Render the baseline underbar/diamond for rows carrying `baselineStart`/`baselineEnd`. */
|
|
6795
7106
|
readonly showBaselines: _angular_core.InputSignal<boolean>;
|
|
7107
|
+
/**
|
|
7108
|
+
* Render a search field in the pinned corner that filters the label tree.
|
|
7109
|
+
*
|
|
7110
|
+
* Filtering preserves tree CONTEXT rather than flattening to a hit list — see
|
|
7111
|
+
* `gantt-search.ts` for why a plain `rows.filter()` silently re-parents matching children and
|
|
7112
|
+
* de-groups matching parents. A live query also expands every group (a match hidden inside a
|
|
7113
|
+
* collapsed summary is indistinguishable from no match at all) and suspends drag-reorder, since
|
|
7114
|
+
* a filtered sibling list is not a complete one to reorder against.
|
|
7115
|
+
*
|
|
7116
|
+
* `null` defers to {@link FlyGanttDefaults.searchable}, then to `false`.
|
|
7117
|
+
*/
|
|
7118
|
+
readonly searchable: _angular_core.InputSignal<boolean | null>;
|
|
7119
|
+
/**
|
|
7120
|
+
* Let the user drag label rows to reorder / re-home them, emitting {@link rowReorder}.
|
|
7121
|
+
*
|
|
7122
|
+
* `null` defers to {@link FlyGanttDefaults.reorderable}, then to `false` — the chart never
|
|
7123
|
+
* offers a gesture whose result nobody is persisting.
|
|
7124
|
+
*/
|
|
7125
|
+
readonly reorderable: _angular_core.InputSignal<boolean | null>;
|
|
7126
|
+
/**
|
|
7127
|
+
* The label-tree filter text. Two-way bindable, so a consumer can seed it from a deep link or
|
|
7128
|
+
* clear it on navigation; the built-in field writes it as the user types (debounced by
|
|
7129
|
+
* `fly-search-input`). Ignored unless {@link searchable}.
|
|
7130
|
+
*/
|
|
7131
|
+
readonly searchQuery: _angular_core.ModelSignal<string>;
|
|
6796
7132
|
/** Fires on a committed bar move / resize with the new ISO `start`/`end`. */
|
|
6797
7133
|
readonly rowDatesChange: _angular_core.OutputEmitterRef<GanttRowDatesChange>;
|
|
6798
7134
|
/**
|
|
@@ -6812,32 +7148,72 @@ declare class FlyGanttComponent {
|
|
|
6812
7148
|
readonly rowExpand: _angular_core.OutputEmitterRef<string>;
|
|
6813
7149
|
/** The component coarsened the requested zoom to stay under `maxCanvasPx`. */
|
|
6814
7150
|
readonly effectiveZoomChange: _angular_core.OutputEmitterRef<GanttZoom>;
|
|
7151
|
+
/**
|
|
7152
|
+
* A label row was dragged to a new place. Carries the complete new sibling order, so a consumer
|
|
7153
|
+
* persists it with one ordered-set write. See {@link GanttRowReorder}.
|
|
7154
|
+
*/
|
|
7155
|
+
readonly rowReorder: _angular_core.OutputEmitterRef<GanttRowReorder>;
|
|
7156
|
+
/**
|
|
7157
|
+
* A row's outline level was nudged by {@link indentRow} / {@link outdentRow}, with the resulting
|
|
7158
|
+
* parent already resolved from the row's neighbours. The chart does not re-render on its own —
|
|
7159
|
+
* like every other gesture here, the consumer persists and feeds new `rows` back in.
|
|
7160
|
+
*/
|
|
7161
|
+
readonly rowIndentChange: _angular_core.OutputEmitterRef<GanttRowIndentChange>;
|
|
6815
7162
|
private readonly _uid;
|
|
6816
7163
|
readonly markerId: string;
|
|
6817
7164
|
readonly HEADER_H: number;
|
|
6818
7165
|
readonly HEADER_UPPER_H = 22;
|
|
6819
7166
|
readonly HEADER_LOWER_H = 22;
|
|
6820
7167
|
readonly HANDLE_W = 8;
|
|
7168
|
+
/** Connector radius — small, and parked outside the bar, so it never steals the resize
|
|
7169
|
+
* handle's press (`gantt-row-vm.ts`'s CONNECTOR_R note). */
|
|
7170
|
+
readonly CONNECTOR_R = 3;
|
|
6821
7171
|
readonly MIN_LABEL_W = 140;
|
|
6822
7172
|
readonly MAX_LABEL_W = 720;
|
|
6823
7173
|
readonly BASELINE_BAR_H: number;
|
|
6824
7174
|
readonly selectedId: _angular_core.WritableSignal<string | null>;
|
|
6825
7175
|
/** Uncontrolled collapse state — the source of truth whenever the `collapsedIds` input is `null`. */
|
|
6826
7176
|
private readonly _uncontrolledCollapsed;
|
|
6827
|
-
/** Live drag preview `{id,start,end}` folded into geometry while a gesture runs
|
|
7177
|
+
/** Live drag preview `{id,start,end}` folded into geometry while a bar gesture runs, and the
|
|
7178
|
+
* cursor-following date readout beside it — both owned by {@link GanttBarDrag}, re-exposed here
|
|
7179
|
+
* because the row geometry reads the first and the template renders the second. */
|
|
6828
7180
|
private readonly _dragPreview;
|
|
6829
|
-
readonly dragTooltip: _angular_core.
|
|
6830
|
-
x: number;
|
|
6831
|
-
y: number;
|
|
6832
|
-
text: string;
|
|
6833
|
-
} | null>;
|
|
7181
|
+
readonly dragTooltip: _angular_core.Signal<GanttDragTooltip | null>;
|
|
6834
7182
|
private readonly bodyRef;
|
|
6835
7183
|
private readonly scrollElRef;
|
|
6836
7184
|
private readonly canvasElRef;
|
|
6837
7185
|
private readonly labelsElRef;
|
|
6838
7186
|
readonly rtl: _angular_core.Signal<boolean>;
|
|
7187
|
+
/** The zoom the consumer asked for, before `maxCanvasPx` coarsening ({@link effectiveZoom}). */
|
|
7188
|
+
readonly requestedZoom: _angular_core.Signal<GanttZoom>;
|
|
7189
|
+
/** Row band height actually rendered. */
|
|
7190
|
+
readonly effectiveRowHeight: _angular_core.Signal<number>;
|
|
7191
|
+
/** The width the label pane falls back to until the user drags the divider. */
|
|
7192
|
+
private readonly _labelWidthInput;
|
|
7193
|
+
/** Whether the corner search field is rendered at all. */
|
|
7194
|
+
readonly searchEnabled: _angular_core.Signal<boolean>;
|
|
7195
|
+
/** The live filter text, or `''` when searching is off — the one signal every filter path reads. */
|
|
7196
|
+
readonly activeQuery: _angular_core.Signal<string>;
|
|
7197
|
+
/**
|
|
7198
|
+
* Whether a label row can be dragged right now.
|
|
7199
|
+
*
|
|
7200
|
+
* Suspended while a search is live, deliberately: {@link rowReorder} emits the COMPLETE sibling
|
|
7201
|
+
* order, and a filtered tree only holds the siblings that matched. Persisting that list would
|
|
7202
|
+
* quietly drop every row the filter is hiding — the sort of data loss whose cause is invisible
|
|
7203
|
+
* afterwards. A read-only chart never reorders either.
|
|
7204
|
+
*/
|
|
7205
|
+
readonly reorderEnabled: _angular_core.Signal<boolean>;
|
|
6839
7206
|
/** Effective collapse set: the controlled input when the consumer supplied one, else internal state. */
|
|
6840
7207
|
private readonly _collapsed;
|
|
7208
|
+
/**
|
|
7209
|
+
* The consumer's rows narrowed by the live search filter (identity-stable when not searching).
|
|
7210
|
+
*
|
|
7211
|
+
* NOTE the domain and the resolved dates below deliberately stay on the UNFILTERED `rows()`: a
|
|
7212
|
+
* timeline whose axis and whose summary spans jumped on every keystroke would make the filter
|
|
7213
|
+
* feel like it was editing the plan. Filtering decides which rows are LISTED, not what the dates
|
|
7214
|
+
* are.
|
|
7215
|
+
*/
|
|
7216
|
+
readonly filteredRows: _angular_core.Signal<readonly GanttRow[]>;
|
|
6841
7217
|
/** Full visible list after tree flatten/collapse (no `maxRows` cap applied yet). */
|
|
6842
7218
|
private readonly _flat;
|
|
6843
7219
|
/** `_flat`, capped at `maxRows` when it is positive — unchanged from the pre-A9 contract. */
|
|
@@ -6877,31 +7253,28 @@ declare class FlyGanttComponent {
|
|
|
6877
7253
|
readonly rowVms: _angular_core.Signal<GanttRowVm[]>;
|
|
6878
7254
|
/** Only the rows carrying a tint, so the band pass does not emit an empty rect per row. */
|
|
6879
7255
|
readonly tintedRows: _angular_core.Signal<GanttRowVm[]>;
|
|
6880
|
-
/**
|
|
6881
|
-
*
|
|
6882
|
-
*
|
|
6883
|
-
*
|
|
6884
|
-
|
|
6885
|
-
|
|
6886
|
-
|
|
7256
|
+
/**
|
|
7257
|
+
* Render-space geometry, in {@link GanttRowGeometry} — the row view-model plus every shape
|
|
7258
|
+
* derived from it. Composed for the same reason as the gestures below it: given a row and the
|
|
7259
|
+
* current scale it answers "where is this and what shape is it", and knows nothing about
|
|
7260
|
+
* selection, collapse, windowing or events. `geo` is public because the TEMPLATE calls it.
|
|
7261
|
+
*/
|
|
7262
|
+
readonly geo: GanttRowGeometry;
|
|
7263
|
+
/** Bar height for the current row height — bound directly by the template. */
|
|
6887
7264
|
readonly barHeight: _angular_core.Signal<number>;
|
|
6888
|
-
barTop(vm: GanttRowVm): number;
|
|
6889
|
-
/** Baseline underbar's top edge — a thin strip directly beneath the main bar. */
|
|
6890
|
-
baselineBarTop(vm: GanttRowVm): number;
|
|
6891
|
-
private milestoneR;
|
|
6892
|
-
/** Diamond polygon points for a milestone marker. */
|
|
6893
|
-
diamondPoints(vm: GanttRowVm): string;
|
|
6894
|
-
/** Hollow outline diamond for a milestone row's baseline date (its own x, same row's y). */
|
|
6895
|
-
baselineDiamondPoints(vm: GanttRowVm): string;
|
|
6896
7265
|
/**
|
|
6897
|
-
*
|
|
6898
|
-
*
|
|
7266
|
+
* Dependency arrows, in {@link GanttLinkVms} — the drawing half of the link surface, paired with
|
|
7267
|
+
* the dragging half in `gantt-link-gestures.ts`. Declared after {@link geo} because it is handed
|
|
7268
|
+
* that instance: both halves of a link resolve through the SAME row geometry the rows draw from,
|
|
7269
|
+
* so an arrow can never land somewhere its own endpoint is not.
|
|
7270
|
+
*
|
|
7271
|
+
* Only arrows whose y-span intersects the row window are built — O(E), not O(N) — and the
|
|
7272
|
+
* predicate is CROSSES, not "both endpoints rendered": an edge with one end scrolled out of the
|
|
7273
|
+
* window still has to be drawn through it (memo §4.3 rule 2).
|
|
6899
7274
|
*/
|
|
6900
|
-
|
|
6901
|
-
/**
|
|
6902
|
-
|
|
6903
|
-
/** Inline-start label indent for a tree depth. */
|
|
6904
|
-
indentFor(depth: number): number;
|
|
7275
|
+
private readonly _linkVms;
|
|
7276
|
+
/** The arrows the template draws. */
|
|
7277
|
+
readonly linkVms: _angular_core.Signal<GanttLinkVm[]>;
|
|
6905
7278
|
/**
|
|
6906
7279
|
* The divider's own state machine, in {@link GanttLabelPane}. It is composed rather than
|
|
6907
7280
|
* inlined because it is the one region of this component with no coupling to the chart: give it
|
|
@@ -6936,12 +7309,42 @@ declare class FlyGanttComponent {
|
|
|
6936
7309
|
onLabelRowKeydown(ev: Event, id: string): void;
|
|
6937
7310
|
onRowClick(id: string): void;
|
|
6938
7311
|
onRowDblClick(id: string): void;
|
|
6939
|
-
|
|
6940
|
-
|
|
6941
|
-
|
|
6942
|
-
|
|
6943
|
-
|
|
6944
|
-
|
|
7312
|
+
/**
|
|
7313
|
+
* Press on a row's own SHAPE — the group bracket today; bars and milestones reach the same place
|
|
7314
|
+
* through {@link onBarPointerDown}, which additionally starts a drag.
|
|
7315
|
+
*
|
|
7316
|
+
* `stopPropagation` is what keeps this apart from the background pan: the full-width lane rect
|
|
7317
|
+
* behind every row is deliberately NOT a selection target any more (clicking the empty part of a
|
|
7318
|
+
* row is a pan, not a pick), so only a press that lands on a painted shape may select.
|
|
7319
|
+
*/
|
|
7320
|
+
onShapePointerDown(ev: PointerEvent, id: string): void;
|
|
7321
|
+
/** Settled (debounced) text from the corner search field. */
|
|
7322
|
+
onSearchQueryChange(query: string): void;
|
|
7323
|
+
onLinkClick(ev: Event, vm: GanttLinkVm): void;
|
|
7324
|
+
/**
|
|
7325
|
+
* Claim the press on a dependency arrow before the canvas can read it as the start of a pan.
|
|
7326
|
+
*
|
|
7327
|
+
* An arrow is a CONTROL sitting on the pan surface, and it selects on `click` — but the pan
|
|
7328
|
+
* gesture swallows the trailing click of any press that travelled more than
|
|
7329
|
+
* `PAN_THRESHOLD_PX`, so on a 1.5px line a perfectly ordinary click (a few pixels of hand
|
|
7330
|
+
* movement between press and release) selected nothing and nudged the chart sideways instead.
|
|
7331
|
+
* The bar drag and the connector drag were never affected because both already stop the press
|
|
7332
|
+
* here; the arrow was the one interactive thing on the canvas that did not.
|
|
7333
|
+
*/
|
|
7334
|
+
onLinkPathPointerDown(ev: PointerEvent): void;
|
|
7335
|
+
/**
|
|
7336
|
+
* Grab the head of the selected arrow and re-point it. Resolves the arrow's SOURCE row, because
|
|
7337
|
+
* that is where the gesture has to originate for the drop to derive a relationship type.
|
|
7338
|
+
*/
|
|
7339
|
+
onLinkHeadPointerDown(ev: PointerEvent, vm: GanttLinkVm): void;
|
|
7340
|
+
deleteLink(ev: Event, vm: GanttLinkVm): void;
|
|
7341
|
+
/**
|
|
7342
|
+
* Moving and resizing a bar, in {@link GanttBarDrag} — the last of the three pointer gestures
|
|
7343
|
+
* to be composed rather than inlined, for the same reason as the other two: it needs a scale, a
|
|
7344
|
+
* direction and somewhere to report a committed pair of dates, and nothing else about the chart.
|
|
7345
|
+
*/
|
|
7346
|
+
private readonly _barDrag;
|
|
7347
|
+
onBarPointerDown(ev: PointerEvent, vm: GanttRowVm, mode: GanttBarDragMode): void;
|
|
6945
7348
|
/**
|
|
6946
7349
|
* The dependency-drawing gesture, in {@link GanttLinkGestures}. Composed rather than inlined
|
|
6947
7350
|
* because it is a self-contained second gesture whose interesting part is a RULE — the end you
|
|
@@ -6955,1584 +7358,1839 @@ declare class FlyGanttComponent {
|
|
|
6955
7358
|
readonly linkGesture: _angular_core.WritableSignal<GanttLinkGesture | null>;
|
|
6956
7359
|
/** Rubber-band path for an in-flight link gesture (render space). */
|
|
6957
7360
|
readonly linkGesturePath: _angular_core.Signal<string | null>;
|
|
6958
|
-
onLinkPointerDown(ev: PointerEvent, vm: GanttRowVm, anchor: GanttLinkAnchor): void;
|
|
6959
7361
|
/**
|
|
6960
|
-
*
|
|
6961
|
-
*
|
|
6962
|
-
*
|
|
7362
|
+
* The chart's keyboard map, in {@link GanttKeyboard} — composed for the same reason as the three
|
|
7363
|
+
* pointer gestures below it. Declared after the link surface because it is handed both halves:
|
|
7364
|
+
* Delete belongs to a selected ARROW before it belongs to a selected row.
|
|
6963
7365
|
*/
|
|
6964
|
-
private
|
|
7366
|
+
private readonly _keyboard;
|
|
7367
|
+
onGridKeydown(ev: KeyboardEvent): void;
|
|
7368
|
+
onLinkPointerDown(ev: PointerEvent, vm: GanttRowVm, anchor: GanttLinkAnchor): void;
|
|
7369
|
+
/**
|
|
7370
|
+
* Ctrl+wheel scrolls horizontally and a press-drag on empty chart space pans, both in
|
|
7371
|
+
* {@link GanttPan}. Composed for the same reason as the other two gestures: it needs a scrolling
|
|
7372
|
+
* element and nothing else about the chart, and its two subtleties (a non-passive wheel listener
|
|
7373
|
+
* is the only kind that can out-vote browser zoom; a pan must swallow its own trailing click)
|
|
7374
|
+
* read better beside each other than scattered through this class.
|
|
7375
|
+
*/
|
|
7376
|
+
private readonly _pan;
|
|
7377
|
+
/** True mid drag-pan — drives the host's grabbing cursor. */
|
|
7378
|
+
readonly panning: _angular_core.WritableSignal<boolean>;
|
|
7379
|
+
/**
|
|
7380
|
+
* Press on the chart background. Every interactive shape stops propagation on its own
|
|
7381
|
+
* `pointerdown`, so only genuinely empty space (the lane rects, the weekend bands, the
|
|
7382
|
+
* gridlines, the canvas itself) ever reaches this.
|
|
7383
|
+
*/
|
|
7384
|
+
onPanPointerDown(ev: PointerEvent): void;
|
|
7385
|
+
/**
|
|
7386
|
+
* The flattened rows in the narrow shape the reorder resolver needs.
|
|
7387
|
+
*
|
|
7388
|
+
* `parentId` is recomputed from the rendered DEPTHS rather than copied off `GanttRow.parentId`,
|
|
7389
|
+
* and the difference is load-bearing: `flattenRows` treats an unknown, self- or cyclic parent as
|
|
7390
|
+
* a root, so a row can render at depth 0 while still carrying a `parentId` string. Trusting the
|
|
7391
|
+
* field would have the resolver build a sibling list for a parent that is not on screen.
|
|
7392
|
+
*/
|
|
7393
|
+
private readonly _reorderRows;
|
|
7394
|
+
private readonly _reorder;
|
|
7395
|
+
/** Id of the row being dragged, or `null`. */
|
|
7396
|
+
readonly reorderDraggingId: _angular_core.WritableSignal<string | null>;
|
|
7397
|
+
/** Absolute row-space `y` of the drop indicator, or `null` when no drag is live. */
|
|
7398
|
+
readonly reorderIndicatorTop: _angular_core.Signal<number | null>;
|
|
7399
|
+
onLabelRowPointerDown(ev: PointerEvent, id: string): void;
|
|
7400
|
+
/** Whether `id` can become a child of the row above it (see `canIndentGanttRow`). */
|
|
7401
|
+
canIndentRow(id: string): boolean;
|
|
7402
|
+
/** Whether `id` can be lifted out of its parent — i.e. whether it has one. */
|
|
7403
|
+
canOutdentRow(id: string): boolean;
|
|
7404
|
+
/** Reactive twins for the currently selected row — what a magic-bar publisher binds to. */
|
|
7405
|
+
readonly canIndentSelected: _angular_core.Signal<boolean>;
|
|
7406
|
+
readonly canOutdentSelected: _angular_core.Signal<boolean>;
|
|
7407
|
+
/** Make `id` a child of the row directly above it, if it has an eligible sibling there. */
|
|
7408
|
+
indentRow(id: string): void;
|
|
7409
|
+
/** Lift `id` out to its grandparent's level (`null` = the root). */
|
|
7410
|
+
outdentRow(id: string): void;
|
|
6965
7411
|
private _mapTicks;
|
|
7412
|
+
/** Bridges the pure a11y label builder to this component's localizer + Date-typed geometry. */
|
|
6966
7413
|
private _ariaFor;
|
|
6967
7414
|
static ɵfac: _angular_core.ɵɵFactoryDeclaration<FlyGanttComponent, never>;
|
|
6968
|
-
static ɵcmp: _angular_core.ɵɵComponentDeclaration<FlyGanttComponent, "fly-gantt", never, { "rows": { "alias": "rows"; "required": false; "isSignal": true; }; "dependencies": { "alias": "dependencies"; "required": false; "isSignal": true; }; "zoom": { "alias": "zoom"; "required": false; "isSignal": true; }; "showToday": { "alias": "showToday"; "required": false; "isSignal": true; }; "readonly": { "alias": "readonly"; "required": false; "isSignal": true; }; "labelWidth": { "alias": "labelWidth"; "required": false; "isSignal": true; }; "resizableLabels": { "alias": "resizableLabels"; "required": false; "isSignal": true; }; "rowHeight": { "alias": "rowHeight"; "required": false; "isSignal": true; }; "maxRows": { "alias": "maxRows"; "required": false; "isSignal": true; }; "collapsedIds": { "alias": "collapsedIds"; "required": false; "isSignal": true; }; "overscanRows": { "alias": "overscanRows"; "required": false; "isSignal": true; }; "maxCanvasPx": { "alias": "maxCanvasPx"; "required": false; "isSignal": true; }; "virtualized": { "alias": "virtualized"; "required": false; "isSignal": true; }; "showBaselines": { "alias": "showBaselines"; "required": false; "isSignal": true; }; }, { "rowDatesChange": "rowDatesChange"; "dependencyCreate": "dependencyCreate"; "dependencyDelete": "dependencyDelete"; "rowClick": "rowClick"; "rowDblClick": "rowDblClick"; "labelWidthChange": "labelWidthChange"; "collapsedIdsChange": "collapsedIdsChange"; "rowExpand": "rowExpand"; "effectiveZoomChange": "effectiveZoomChange"; }, never, never, true, never>;
|
|
7415
|
+
static ɵcmp: _angular_core.ɵɵComponentDeclaration<FlyGanttComponent, "fly-gantt", never, { "rows": { "alias": "rows"; "required": false; "isSignal": true; }; "dependencies": { "alias": "dependencies"; "required": false; "isSignal": true; }; "zoom": { "alias": "zoom"; "required": false; "isSignal": true; }; "showToday": { "alias": "showToday"; "required": false; "isSignal": true; }; "readonly": { "alias": "readonly"; "required": false; "isSignal": true; }; "labelWidth": { "alias": "labelWidth"; "required": false; "isSignal": true; }; "resizableLabels": { "alias": "resizableLabels"; "required": false; "isSignal": true; }; "rowHeight": { "alias": "rowHeight"; "required": false; "isSignal": true; }; "maxRows": { "alias": "maxRows"; "required": false; "isSignal": true; }; "collapsedIds": { "alias": "collapsedIds"; "required": false; "isSignal": true; }; "overscanRows": { "alias": "overscanRows"; "required": false; "isSignal": true; }; "maxCanvasPx": { "alias": "maxCanvasPx"; "required": false; "isSignal": true; }; "virtualized": { "alias": "virtualized"; "required": false; "isSignal": true; }; "showBaselines": { "alias": "showBaselines"; "required": false; "isSignal": true; }; "searchable": { "alias": "searchable"; "required": false; "isSignal": true; }; "reorderable": { "alias": "reorderable"; "required": false; "isSignal": true; }; "searchQuery": { "alias": "searchQuery"; "required": false; "isSignal": true; }; }, { "searchQuery": "searchQueryChange"; "rowDatesChange": "rowDatesChange"; "dependencyCreate": "dependencyCreate"; "dependencyDelete": "dependencyDelete"; "rowClick": "rowClick"; "rowDblClick": "rowDblClick"; "labelWidthChange": "labelWidthChange"; "collapsedIdsChange": "collapsedIdsChange"; "rowExpand": "rowExpand"; "effectiveZoomChange": "effectiveZoomChange"; "rowReorder": "rowReorder"; "rowIndentChange": "rowIndentChange"; }, never, never, true, never>;
|
|
6969
7416
|
}
|
|
6970
7417
|
|
|
6971
|
-
/** The 14 rendered field kinds. Drives the control the renderer picks. */
|
|
6972
|
-
type FlyFormQuestionType = 'Text' | 'MultilineText' | 'Number' | 'Email' | 'Date' | 'DateTime' | 'Boolean' | 'SingleSelect' | 'MultipleSelect' | 'RadioButton' | 'Country' | 'File' | 'MultiFile' | 'Image';
|
|
6973
|
-
/**
|
|
6974
|
-
* A selectable option on a choice field (SingleSelect / MultipleSelect /
|
|
6975
|
-
* RadioButton). `linkedQuestionIds` drive conditional branching: selecting this
|
|
6976
|
-
* option reveals those (branch-target) fields. `score` is author-only and is only
|
|
6977
|
-
* surfaced to the viewer when the host opts in via `[showScore]` (a scorecard);
|
|
6978
|
-
* a respondent-facing form leaves `showScore` false and never renders it.
|
|
6979
|
-
*/
|
|
6980
|
-
interface FlyFormOption {
|
|
6981
|
-
id: string;
|
|
6982
|
-
label: string;
|
|
6983
|
-
score?: number;
|
|
6984
|
-
linkedQuestionIds?: string[];
|
|
6985
|
-
}
|
|
6986
|
-
/** Per-type constraints/affordances an author can attach to a field. */
|
|
6987
|
-
interface FlyFormFieldOptions {
|
|
6988
|
-
minLength?: number;
|
|
6989
|
-
maxLength?: number;
|
|
6990
|
-
numericMin?: number;
|
|
6991
|
-
numericMax?: number;
|
|
6992
|
-
rows?: number;
|
|
6993
|
-
maxFileSizeMb?: number;
|
|
6994
|
-
maxFileCount?: number;
|
|
6995
|
-
allowedExtensions?: string[];
|
|
6996
|
-
hasSearch?: boolean;
|
|
6997
|
-
}
|
|
6998
7418
|
/**
|
|
6999
|
-
*
|
|
7000
|
-
*
|
|
7001
|
-
*
|
|
7419
|
+
* App-level defaults for every {@link FlyGanttComponent} under a given injector.
|
|
7420
|
+
*
|
|
7421
|
+
* ## Why a token and not "just use the input"
|
|
7422
|
+
* Every field here is already a per-instance `input()`, and for a one-off chart that is the right
|
|
7423
|
+
* knob. But a planning app draws the SAME chart on four or five screens (a project plan, a
|
|
7424
|
+
* schedule, a portfolio roadmap, a programme rollup), and the presentation decisions — how wide the
|
|
7425
|
+
* label pane starts, how tall a row band is, whether the label pane is searchable — are properties
|
|
7426
|
+
* of the APP, not of any one screen. Repeating them at every call site is how the fifth screen ends
|
|
7427
|
+
* up with a 240px pane while the other four use 360, with no single place that says which is right.
|
|
7428
|
+
*
|
|
7429
|
+
* So: provide once at the app (or a feature-area) injector, override per instance where a screen
|
|
7430
|
+
* genuinely differs. An explicit input ALWAYS wins over the token, and the token over the built-in
|
|
7431
|
+
* default — the plain three-step precedence, stated once in `FlyGanttComponent`'s resolvers.
|
|
7432
|
+
*
|
|
7433
|
+
* ```ts
|
|
7434
|
+
* // app.config.ts
|
|
7435
|
+
* providers: [provideFlyGanttDefaults({ labelWidth: 360, searchable: true })]
|
|
7436
|
+
* ```
|
|
7437
|
+
*
|
|
7438
|
+
* Every field is optional: a partial object overrides only what it names, so an app can move the
|
|
7439
|
+
* label width without also inheriting an opinion about row height.
|
|
7002
7440
|
*/
|
|
7003
|
-
interface
|
|
7004
|
-
|
|
7005
|
-
|
|
7006
|
-
|
|
7007
|
-
|
|
7008
|
-
|
|
7009
|
-
|
|
7010
|
-
|
|
7011
|
-
|
|
7012
|
-
|
|
7013
|
-
|
|
7014
|
-
|
|
7015
|
-
/**
|
|
7016
|
-
|
|
7017
|
-
/** Additive: labels the weighted-criteria group a scored field belongs to. Ignored by surveys. */
|
|
7018
|
-
criteriaGroup?: string;
|
|
7019
|
-
}
|
|
7020
|
-
/** A full form definition — the top-level `[definition]` binding. */
|
|
7021
|
-
interface FlyFormDefinition {
|
|
7022
|
-
title: string;
|
|
7023
|
-
description?: string;
|
|
7024
|
-
declaration?: string;
|
|
7025
|
-
questions: FlyFormQuestion[];
|
|
7441
|
+
interface FlyGanttDefaults {
|
|
7442
|
+
/**
|
|
7443
|
+
* Initial inline-start label-pane width in px, before the user drags the divider. Clamped into
|
|
7444
|
+
* `[GANTT_LABEL_W_MIN, GANTT_LABEL_W_MAX]` like every other width source.
|
|
7445
|
+
*/
|
|
7446
|
+
readonly labelWidth?: number;
|
|
7447
|
+
/** Row band height in px. */
|
|
7448
|
+
readonly rowHeight?: number;
|
|
7449
|
+
/** Time-grid resolution a chart opens at. */
|
|
7450
|
+
readonly zoom?: GanttZoom;
|
|
7451
|
+
/** Render the label-pane search field (see `FlyGanttComponent.searchable`). */
|
|
7452
|
+
readonly searchable?: boolean;
|
|
7453
|
+
/** Allow dragging label rows to reorder them (see `FlyGanttComponent.reorderable`). */
|
|
7454
|
+
readonly reorderable?: boolean;
|
|
7026
7455
|
}
|
|
7027
|
-
/** How an opted-in `[showScore]` host renders a choice option's points. */
|
|
7028
|
-
type FlyFormScoreDisplay = 'inline' | 'badge';
|
|
7029
7456
|
/**
|
|
7030
|
-
*
|
|
7031
|
-
*
|
|
7032
|
-
* - text: Text / MultilineText / Email
|
|
7033
|
-
* - number: Number
|
|
7034
|
-
* - dateValue: Date / DateTime (raw `<input>` value string)
|
|
7035
|
-
* - boolValue: Boolean
|
|
7036
|
-
* - selectedOptionIds: SingleSelect / MultipleSelect / RadioButton / Country
|
|
7037
|
-
* - fileIds: File / MultiFile / Image (filled by the host after upload; this
|
|
7038
|
-
* component emits it empty and surfaces the raw selection via `fileSelected`)
|
|
7457
|
+
* DI token carrying {@link FlyGanttDefaults}. Optional everywhere — a chart with no provider falls
|
|
7458
|
+
* back to the component's own built-in defaults, which is what every pre-existing consumer gets.
|
|
7039
7459
|
*/
|
|
7040
|
-
|
|
7041
|
-
|
|
7042
|
-
|
|
7043
|
-
|
|
7044
|
-
|
|
7045
|
-
|
|
7046
|
-
|
|
7047
|
-
}
|
|
7048
|
-
/** One field's answer — the unit emitted by `answersChange` / `submit`. */
|
|
7049
|
-
interface FlyFormAnswer {
|
|
7050
|
-
questionId: string;
|
|
7051
|
-
value: FlyFormAnswerValue;
|
|
7052
|
-
}
|
|
7460
|
+
declare const FLY_GANTT_DEFAULTS: InjectionToken<FlyGanttDefaults>;
|
|
7461
|
+
/** Provider helper — `providers: [provideFlyGanttDefaults({ labelWidth: 360 })]`. */
|
|
7462
|
+
declare function provideFlyGanttDefaults(defaults: FlyGanttDefaults): Provider;
|
|
7463
|
+
|
|
7464
|
+
/** Label-pane width bounds (px) the splitter clamps to. */
|
|
7465
|
+
declare const GANTT_LABEL_W_MIN = 140;
|
|
7466
|
+
declare const GANTT_LABEL_W_MAX = 720;
|
|
7053
7467
|
/**
|
|
7054
|
-
*
|
|
7055
|
-
*
|
|
7056
|
-
*
|
|
7468
|
+
* Width (px) a label pane opens at when neither the consumer's `labelWidth` input nor an app-level
|
|
7469
|
+
* `FlyGanttDefaults` says otherwise.
|
|
7470
|
+
*
|
|
7471
|
+
* Raised from the original 240. A Gantt label is a full work-breakdown title, routinely carrying a
|
|
7472
|
+
* prefix the consumer composed in (PPM puts the assignee's initials on every task row and a weight
|
|
7473
|
+
* suffix on every milestone), and at 240px the ellipsis landed inside the NAME for a majority of
|
|
7474
|
+
* real rows — which turns the pane into a list of indistinguishable truncations rather than a
|
|
7475
|
+
* readable outline. It remains an INITIAL value only: the divider drag, the keyboard resize and
|
|
7476
|
+
* `resetLabelWidth()` all behave exactly as before.
|
|
7057
7477
|
*/
|
|
7058
|
-
|
|
7059
|
-
questionId: string;
|
|
7060
|
-
files: File[];
|
|
7061
|
-
}
|
|
7478
|
+
declare const GANTT_LABEL_W_DEFAULT = 320;
|
|
7062
7479
|
|
|
7063
|
-
/** A render segment: either an ungrouped field (`group === null`) or a titled `criteriaGroup` section.
|
|
7064
|
-
* `index` is the field's running position across the whole form (drives unique element ids). */
|
|
7065
|
-
interface FlyFormFieldGroup {
|
|
7066
|
-
group: string | null;
|
|
7067
|
-
items: {
|
|
7068
|
-
q: FlyFormQuestion;
|
|
7069
|
-
index: number;
|
|
7070
|
-
}[];
|
|
7071
|
-
}
|
|
7072
7480
|
/**
|
|
7073
|
-
*
|
|
7074
|
-
*
|
|
7075
|
-
* Renders a {@link FlyFormDefinition} (14 field types) into an accessible,
|
|
7076
|
-
* theme-aware form, owning all the fiddly behaviour a form needs: conditional
|
|
7077
|
-
* **branching** (options reveal branch-target fields), per-visible-field
|
|
7078
|
-
* **required validation**, a **declaration** acceptance gate, and a **readonly**
|
|
7079
|
-
* replay mode. It is a platform surface — zero coupling to any specific app, and
|
|
7080
|
-
* (deliberately) no coupling to an upload API: File / Image / MultiFile fields
|
|
7081
|
-
* surface the raw selection via {@link fileSelected} and emit `fileIds` empty; the
|
|
7082
|
-
* host wires the upload and feeds ids back through the `[answers]` prefill.
|
|
7481
|
+
* Magic-bar contribution contract (UX v2 "Nova", D5 §4).
|
|
7083
7482
|
*
|
|
7084
|
-
* The
|
|
7085
|
-
* (
|
|
7086
|
-
*
|
|
7087
|
-
*
|
|
7088
|
-
* `
|
|
7483
|
+
* The magic bar is the shell's top-bar toolbar pill. Unlike the fixed right
|
|
7484
|
+
* cluster (Help / Tasks / Notifications / assistant orb — shell-owned, an app can
|
|
7485
|
+
* never remove it), the pill's contents belong to **whatever view the user is
|
|
7486
|
+
* looking at**, and the design's reference implementation re-publishes the whole
|
|
7487
|
+
* set on every selection, tab and save (`pubTabActions`). Two consequences shape
|
|
7488
|
+
* every type below:
|
|
7089
7489
|
*
|
|
7090
|
-
*
|
|
7091
|
-
*
|
|
7092
|
-
*
|
|
7093
|
-
*
|
|
7094
|
-
*
|
|
7490
|
+
* 1. **A contribution is a full replace, never a patch.** There is no "add one
|
|
7491
|
+
* action" call, because the publisher never knows what the previous view left
|
|
7492
|
+
* behind. That also collapses D5's `search: null` ("suppress") vs `search`
|
|
7493
|
+
* absent distinction — under full replace both simply mean "this view offers
|
|
7494
|
+
* no search".
|
|
7495
|
+
* 2. **Render data and behaviour are separated in the type system.** Each family
|
|
7496
|
+
* has a `*Spec` base carrying ONLY the fields that affect what is painted;
|
|
7497
|
+
* the publisher-facing type extends it with callbacks, and the shell-facing
|
|
7498
|
+
* `*View` type extends it with bound invokers. The base IS the equality
|
|
7499
|
+
* surface {@link MagicBarRegistry} dedupes on — a re-publish whose specs are
|
|
7500
|
+
* unchanged must not disturb the shell, even though its closures are brand
|
|
7501
|
+
* new objects every time (an arrow function in a component method never
|
|
7502
|
+
* compares equal to its predecessor). See `magic-bar-projection.ts`.
|
|
7095
7503
|
*
|
|
7096
|
-
*
|
|
7097
|
-
*
|
|
7098
|
-
*
|
|
7099
|
-
*
|
|
7100
|
-
*
|
|
7101
|
-
*
|
|
7102
|
-
*
|
|
7103
|
-
*
|
|
7104
|
-
*
|
|
7105
|
-
*
|
|
7106
|
-
*
|
|
7504
|
+
* **Strings are i18n keys, never resolved text** — same rule as
|
|
7505
|
+
* {@link AgentCommandRegistration} (`labelKey` / `descriptionKey` / `hintKey`),
|
|
7506
|
+
* for the same two reasons: a contribution outlives a locale switch (a resolved
|
|
7507
|
+
* label would silently go stale until the publisher happened to re-publish), and
|
|
7508
|
+
* keys are locale-invariant so the dedupe fingerprint doesn't churn when the user
|
|
7509
|
+
* changes language. Keys resolve in the OWNING app's bundle.
|
|
7510
|
+
*
|
|
7511
|
+
* **Every `*Key` has an optional `*Params` sibling** ({@link MagicBarTextParams}),
|
|
7512
|
+
* fed straight to `I18nService.t(key, params)`. Without it a count-carrying string
|
|
7513
|
+
* ("Search 1,204 tasks…") forces the publisher to pass pre-formatted TEXT as the
|
|
7514
|
+
* key: it renders correctly in `en`, renders identically untranslated in ar/fr/ur,
|
|
7515
|
+
* and no locale tool can see it. Params participate in the dedupe fingerprint, so
|
|
7516
|
+
* a changing count re-paints.
|
|
7517
|
+
*
|
|
7518
|
+
* Which of D5 §4's "dynamics the shell must honor" live where:
|
|
7519
|
+
*
|
|
7520
|
+
* | # | Dynamic | Owner |
|
|
7521
|
+
* |---|---|---|
|
|
7522
|
+
* | 1 | Live re-publication, idempotent replace | {@link MagicBarRegistry} (here) |
|
|
7523
|
+
* | 2 | Disabled ≠ hidden, auto disabled-tooltip | contract keeps `disabled` rows; `fly-magic-actions` renders + suffixes |
|
|
7524
|
+
* | 3 | `toolbarPopIn` 40 ms stagger | renderer — it tracks on {@link MagicBarActionSpec.id}, which is why ids are unique across the WHOLE contribution |
|
|
7525
|
+
* | 4 | i18n on every label/tip | contract (keys + params, above) |
|
|
7526
|
+
* | 5 | Fixed right cluster is not contributable | contract — no slot exists for it |
|
|
7527
|
+
* | 6 | Mobile renders the same contribution | contract carries no form-factor branch; `openWidth` is a desktop hint mobile ignores |
|
|
7528
|
+
* | 7 | `shortcut` reserved (design has no shortcut affordance yet) | contract — carried, unrendered |
|
|
7529
|
+
*
|
|
7530
|
+
* On dynamic 3 specifically: the registry's dedupe does NOT stop the stagger
|
|
7531
|
+
* replaying, and believing it does would produce a renderer that re-animates on
|
|
7532
|
+
* every click. Dedupe fires only when *nothing painted* changed, and the dominant
|
|
7533
|
+
* case — `disabled: !hasSelection` — changes the fingerprint on every selection.
|
|
7534
|
+
* What holds the DOM still is the renderer's `@for (…; track item.id)`.
|
|
7107
7535
|
*/
|
|
7108
|
-
|
|
7109
|
-
|
|
7110
|
-
|
|
7111
|
-
|
|
7112
|
-
|
|
7113
|
-
|
|
7114
|
-
|
|
7115
|
-
|
|
7116
|
-
|
|
7117
|
-
|
|
7118
|
-
|
|
7119
|
-
|
|
7120
|
-
|
|
7121
|
-
|
|
7122
|
-
|
|
7123
|
-
|
|
7124
|
-
|
|
7125
|
-
|
|
7126
|
-
|
|
7127
|
-
|
|
7128
|
-
|
|
7129
|
-
|
|
7130
|
-
|
|
7131
|
-
|
|
7132
|
-
|
|
7133
|
-
|
|
7134
|
-
|
|
7135
|
-
|
|
7136
|
-
|
|
7137
|
-
|
|
7138
|
-
|
|
7139
|
-
|
|
7140
|
-
|
|
7141
|
-
|
|
7142
|
-
|
|
7143
|
-
|
|
7144
|
-
|
|
7145
|
-
|
|
7146
|
-
|
|
7147
|
-
|
|
7148
|
-
|
|
7149
|
-
|
|
7150
|
-
|
|
7151
|
-
|
|
7152
|
-
|
|
7153
|
-
|
|
7154
|
-
|
|
7155
|
-
|
|
7536
|
+
/**
|
|
7537
|
+
* How an action paints. `'text'` is the labelled-pill form (calendar's "Today").
|
|
7538
|
+
*
|
|
7539
|
+
* `kind` and {@link MagicBarActionSpec.iconPath} are INDEPENDENT, and the three useful
|
|
7540
|
+
* combinations are all reachable:
|
|
7541
|
+
*
|
|
7542
|
+
* | `kind` | `iconPath` | Paints |
|
|
7543
|
+
* |---|---|---|
|
|
7544
|
+
* | absent / `'icon'` | set | icon only — the default, for a verb with a universally-read glyph |
|
|
7545
|
+
* | `'text'` | absent | label only — for a value with no honest glyph ("Shortlisted", "Deferred") |
|
|
7546
|
+
* | `'text'` | set | **icon + label** — for a verb whose glyph needs naming ("Promote to schedule") |
|
|
7547
|
+
*
|
|
7548
|
+
* Prefer icon-only for the small set of verbs a user reads without help — add, edit, delete, close,
|
|
7549
|
+
* save. Anything else earns its label: an unlabelled glyph the reader has to hover to identify is a
|
|
7550
|
+
* quiz, and the tooltip is not an answer on touch.
|
|
7551
|
+
*/
|
|
7552
|
+
type MagicBarActionKind = 'icon' | 'text' | 'toggle';
|
|
7553
|
+
/**
|
|
7554
|
+
* Semantic colour of an action. `'danger'` is the red Delete treatment (red glyph
|
|
7555
|
+
* + red 18 % hover tint, D7); `'success'` is the green "Mark as complete" pressed
|
|
7556
|
+
* state (D5 §1.4 + §4 prop table: "pressed bg tint-sel / green for complete").
|
|
7557
|
+
*
|
|
7558
|
+
* A union rather than the boolean `danger` this started as: the design already
|
|
7559
|
+
* demands a second colour, and widening a shipped `danger?: boolean` into a union
|
|
7560
|
+
* later would mean REMOVING an interface member — MAJOR under `tools/ds-compat`
|
|
7561
|
+
* (rule 7), which forks the federation singleton for every remote.
|
|
7562
|
+
*/
|
|
7563
|
+
type MagicBarTone = 'default' | 'danger' | 'success';
|
|
7564
|
+
/**
|
|
7565
|
+
* Interpolation params for one i18n key — the `params` argument of
|
|
7566
|
+
* `I18nService.t(key, params)`, substituting `{{name}}` placeholders.
|
|
7567
|
+
*
|
|
7568
|
+
* Values are `string | number` only: the fingerprint has to encode them, and the
|
|
7569
|
+
* renderer resolves them through `t()`, which stringifies. A `Date` or a nested
|
|
7570
|
+
* object would fingerprint as `{}` and paint as `[object Object]`.
|
|
7571
|
+
*/
|
|
7572
|
+
type MagicBarTextParams = Readonly<Record<string, string | number>>;
|
|
7573
|
+
/**
|
|
7574
|
+
* Identity of a contribution's publisher, and the arbitration key the shell uses
|
|
7575
|
+
* to pick which contribution the bar renders.
|
|
7576
|
+
*
|
|
7577
|
+
* `windowId` is optional but strongly preferred: two windows of the same app can
|
|
7578
|
+
* be open on different selections, and keying on `appId` alone would let the
|
|
7579
|
+
* background one paint the focused one's toolbar. It is optional only because a
|
|
7580
|
+
* federated remote that predates per-window plumbing can still contribute —
|
|
7581
|
+
* {@link MagicBarRegistry} resolves an `appId`-keyed slot as a fallback.
|
|
7582
|
+
*
|
|
7583
|
+
* It only has to be unique **within the publishing app** (the shell passes its own
|
|
7584
|
+
* `win-<appId>-<timestamp>` window id; a tab index or a route-derived id is equally
|
|
7585
|
+
* valid) — {@link magicBarOwnerKey} scopes it by `appId`, so a value another app
|
|
7586
|
+
* also uses can never cross over.
|
|
7587
|
+
*/
|
|
7588
|
+
interface MagicBarOwnerRef {
|
|
7589
|
+
readonly appId: string;
|
|
7590
|
+
readonly windowId?: string;
|
|
7591
|
+
}
|
|
7592
|
+
/**
|
|
7593
|
+
* Storage/arbitration key for an owner. Exported because the shell computes it
|
|
7594
|
+
* on the janitor path (`clear` after a window closes) without holding the
|
|
7595
|
+
* publisher.
|
|
7596
|
+
*
|
|
7597
|
+
* **Both fields key the slot**, even though the shell's own ids
|
|
7598
|
+
* (`win-<appId>-<timestamp>`) are already unique. `windowId` is publisher-supplied
|
|
7599
|
+
* DATA that crosses the federation boundary, and the field is documented only as
|
|
7600
|
+
* "two windows of the same app" — nothing stops a remote passing a tab index or a
|
|
7601
|
+
* route-derived id. Keyed on `windowId` alone, two apps that both call their first
|
|
7602
|
+
* window `"1"` would share a slot: one silently paints the other's chrome, and the
|
|
7603
|
+
* shell's janitor `clear()` wipes the wrong one.
|
|
7604
|
+
*/
|
|
7605
|
+
declare function magicBarOwnerKey(owner: MagicBarOwnerRef): string;
|
|
7606
|
+
/** One `menuitemradio` row. `value` is the publisher's own vocabulary. */
|
|
7607
|
+
interface MagicBarRadioOption {
|
|
7608
|
+
readonly value: string;
|
|
7156
7609
|
/**
|
|
7157
|
-
*
|
|
7158
|
-
* (
|
|
7159
|
-
*
|
|
7160
|
-
*
|
|
7610
|
+
* i18n key for this row. Required, and it stays required — the overwhelming case is a fixed
|
|
7611
|
+
* vocabulary (statuses, sort orders) that MUST translate. When {@link label} is supplied this
|
|
7612
|
+
* is the accessible fallback used if the row's data-derived text is ever empty, so give it a
|
|
7613
|
+
* generic key ("Untitled") rather than inventing a per-value one.
|
|
7161
7614
|
*/
|
|
7162
|
-
readonly
|
|
7163
|
-
|
|
7164
|
-
|
|
7165
|
-
readonly isValid: _angular_core.Signal<boolean>;
|
|
7166
|
-
/** Whether `(submit)` may fire: valid required set AND declaration accepted (if any). */
|
|
7167
|
-
readonly canSubmit: _angular_core.Signal<boolean>;
|
|
7168
|
-
readonly declarationAccepted: _angular_core.Signal<boolean>;
|
|
7169
|
-
fieldId(index: number): string;
|
|
7170
|
-
descId(index: number): string;
|
|
7171
|
-
errId(index: number): string;
|
|
7172
|
-
describedBy(q: FlyFormQuestion, index: number): string | null;
|
|
7173
|
-
isChoice(type: FlyFormQuestionType): boolean;
|
|
7174
|
-
isFile(type: FlyFormQuestionType): boolean;
|
|
7175
|
-
/** Types rendered as a native input group inside `<fieldset><legend>`. */
|
|
7176
|
-
isFieldset(type: FlyFormQuestionType): boolean;
|
|
7177
|
-
isCountry(type: FlyFormQuestionType): boolean;
|
|
7615
|
+
readonly labelKey: string;
|
|
7616
|
+
/** Params for {@link labelKey} — the count-badged option ("All statuses ({{count}})"). */
|
|
7617
|
+
readonly labelParams?: MagicBarTextParams;
|
|
7178
7618
|
/**
|
|
7179
|
-
*
|
|
7619
|
+
* ALREADY-RESOLVED display text, for a row whose label is TENANT DATA rather than a caption —
|
|
7620
|
+
* a campaign name, an area of focus, an owner. When present it wins over {@link labelKey}.
|
|
7180
7621
|
*
|
|
7181
|
-
*
|
|
7182
|
-
*
|
|
7183
|
-
*
|
|
7184
|
-
*
|
|
7185
|
-
*
|
|
7622
|
+
* ## Why this had to exist
|
|
7623
|
+
* Everything else in this contract is an i18n key, deliberately (see the module header). But a
|
|
7624
|
+
* key can only name a string the APP ships in its locale bundles, and a tenant's campaign names
|
|
7625
|
+
* are rows in their database. Without this field a publisher had exactly two bad options: put
|
|
7626
|
+
* the name in `labelKey`, which renders correctly in `en`, renders identically untranslated in
|
|
7627
|
+
* ar/fr/ur, and is invisible to every locale tool; or leave the filter out of the bar entirely.
|
|
7628
|
+
* Thoughts' `top-trending` chose the second and kept its campaign/area filters in-page — that
|
|
7629
|
+
* is the gap this closes.
|
|
7630
|
+
*
|
|
7631
|
+
* ## What it does NOT license
|
|
7632
|
+
* Do not use it for captions. If the string is something your app authored — "All statuses",
|
|
7633
|
+
* "Newest first", an action name — it belongs in a locale bundle and `labelKey` is the field.
|
|
7634
|
+
* The test is where the string comes from: shipped with the app ⇒ `labelKey`; read from the
|
|
7635
|
+
* tenant's data ⇒ `label`. A resolved caption here is untranslatable text smuggled past the
|
|
7636
|
+
* locale tooling, which is precisely what the key-only rule exists to prevent.
|
|
7637
|
+
*
|
|
7638
|
+
* It participates in the dedupe fingerprint, so a renamed campaign repaints.
|
|
7186
7639
|
*/
|
|
7187
|
-
|
|
7188
|
-
|
|
7189
|
-
|
|
7640
|
+
readonly label?: string;
|
|
7641
|
+
}
|
|
7642
|
+
/** Render surface of a radio menu — the dedupe key for {@link MagicBarRadioMenu}. */
|
|
7643
|
+
interface MagicBarRadioMenuSpec {
|
|
7644
|
+
/** Eyebrow above the options ("Filter by status" / "Sort by"). */
|
|
7645
|
+
readonly titleKey: string;
|
|
7646
|
+
/** Params for {@link titleKey}. */
|
|
7647
|
+
readonly titleParams?: MagicBarTextParams;
|
|
7648
|
+
readonly options: readonly MagicBarRadioOption[];
|
|
7649
|
+
/** Current selection — check glyph + 600 weight on the matching row. */
|
|
7650
|
+
readonly value: string;
|
|
7651
|
+
/** The unfiltered/unsorted baseline; the trigger shows its accent dot iff `value !== defaultValue`. */
|
|
7652
|
+
readonly defaultValue: string;
|
|
7653
|
+
}
|
|
7654
|
+
/** What a publisher supplies for a radio menu. */
|
|
7655
|
+
interface MagicBarRadioMenu extends MagicBarRadioMenuSpec {
|
|
7656
|
+
readonly onSelect?: (value: string) => void;
|
|
7657
|
+
}
|
|
7658
|
+
/** What the shell renders. `select` always exists; it no-ops when the publisher supplied no handler. */
|
|
7659
|
+
interface MagicBarRadioMenuView extends MagicBarRadioMenuSpec {
|
|
7660
|
+
select(value: string): void;
|
|
7661
|
+
}
|
|
7662
|
+
/**
|
|
7663
|
+
* Render surface of an action — the dedupe key for {@link MagicBarAction}.
|
|
7664
|
+
*
|
|
7665
|
+
* `id` must be unique across the WHOLE contribution (every group, plus `primary`
|
|
7666
|
+
* and `overflow`), not merely within its group: it is the address the shell's
|
|
7667
|
+
* invoker resolves against the publisher's latest handlers.
|
|
7668
|
+
*/
|
|
7669
|
+
interface MagicBarActionSpec {
|
|
7670
|
+
readonly id: string;
|
|
7671
|
+
/** i18n key — the `aria-label` and the default tooltip. */
|
|
7672
|
+
readonly labelKey: string;
|
|
7673
|
+
/** Params for {@link labelKey}, e.g. `{ count: 3 }` for "Delete {{count}} items". */
|
|
7674
|
+
readonly labelParams?: MagicBarTextParams;
|
|
7190
7675
|
/**
|
|
7191
|
-
*
|
|
7192
|
-
*
|
|
7193
|
-
*
|
|
7676
|
+
* Inner-SVG geometry for a 24×24 glyph (`stroke-width: 1.8`, round caps) —
|
|
7677
|
+
* the design's icon transport. Reference {@link FLY_MAGIC_BAR_ICONS} by name
|
|
7678
|
+
* rather than hand-authoring; a publisher MAY author its own, subject to the
|
|
7679
|
+
* contract below.
|
|
7680
|
+
*
|
|
7681
|
+
* **This value is not trusted.** The renderer parses it against a closed
|
|
7682
|
+
* allowlist — self-closing `path`/`circle`/`rect`/`ellipse`/`line`/`polyline`/
|
|
7683
|
+
* `polygon` elements carrying geometry attributes only (`d`, `cx`, `points`,
|
|
7684
|
+
* …) — and binds the result as real attributes. It is never assigned as HTML.
|
|
7685
|
+
* Anything else (a container element, an `on*` handler, `style`, `href`,
|
|
7686
|
+
* `fill="url(…)"`, a stray text node) rejects the WHOLE fragment: the button
|
|
7687
|
+
* renders with no glyph and logs. See `magic-actions-icon.ts`.
|
|
7688
|
+
*
|
|
7689
|
+
* The type stays `string` deliberately. Narrowing it to a branded/opaque type
|
|
7690
|
+
* would be a ds-compat MAJOR, and it would not buy anything the renderer's own
|
|
7691
|
+
* validation does not already guarantee — a nominal type describes where a
|
|
7692
|
+
* value came from, not what it contains.
|
|
7194
7693
|
*/
|
|
7195
|
-
|
|
7196
|
-
/**
|
|
7197
|
-
|
|
7198
|
-
|
|
7199
|
-
|
|
7200
|
-
numberValue(q: FlyFormQuestion): number | null;
|
|
7201
|
-
dateValue(q: FlyFormQuestion): string;
|
|
7202
|
-
boolValue(q: FlyFormQuestion): boolean | null;
|
|
7203
|
-
singleValue(q: FlyFormQuestion): string | null;
|
|
7204
|
-
isSelected(q: FlyFormQuestion, optionId: string): boolean;
|
|
7205
|
-
countryOptions(q: FlyFormQuestion): readonly FlySelectOption[];
|
|
7206
|
-
selectOptions(q: FlyFormQuestion): readonly FlySelectOption[];
|
|
7207
|
-
fileNames(q: FlyFormQuestion): string[];
|
|
7208
|
-
acceptFor(q: FlyFormQuestion): string;
|
|
7209
|
-
onText(q: FlyFormQuestion, value: string): void;
|
|
7210
|
-
onNumber(q: FlyFormQuestion, value: string): void;
|
|
7211
|
-
onDate(q: FlyFormQuestion, value: string): void;
|
|
7212
|
-
onBoolean(q: FlyFormQuestion, value: boolean): void;
|
|
7213
|
-
onSingleSelect(q: FlyFormQuestion, value: string | readonly string[] | null): void;
|
|
7214
|
-
onRadio(q: FlyFormQuestion, optionId: string): void;
|
|
7215
|
-
onMultiToggle(q: FlyFormQuestion, optionId: string, checked: boolean): void;
|
|
7216
|
-
onFiles(q: FlyFormQuestion, input: HTMLInputElement): void;
|
|
7217
|
-
onDeclarationToggle(checked: boolean): void;
|
|
7218
|
-
onSubmit(): void;
|
|
7219
|
-
private _touch;
|
|
7220
|
-
private _setFileError;
|
|
7221
|
-
private _mutate;
|
|
7222
|
-
private _emit;
|
|
7223
|
-
private _collectAnswers;
|
|
7224
|
-
private _isAnswered;
|
|
7225
|
-
private _isEmptyValue;
|
|
7226
|
-
private _selectedIds;
|
|
7694
|
+
readonly iconPath?: string;
|
|
7695
|
+
/** Default `'icon'`. */
|
|
7696
|
+
readonly kind?: MagicBarActionKind;
|
|
7697
|
+
/** Dimmed (`opacity .38`), NEVER hidden — a vanishing action teaches the user nothing. */
|
|
7698
|
+
readonly disabled?: boolean;
|
|
7227
7699
|
/**
|
|
7228
|
-
*
|
|
7229
|
-
*
|
|
7230
|
-
*
|
|
7231
|
-
*
|
|
7232
|
-
|
|
7700
|
+
* Tooltip override while disabled. Absent is the normal case: the renderer
|
|
7701
|
+
* auto-suffixes the resolved label ("… — select an item first"). Resolution
|
|
7702
|
+
* and the connector phrasing are the renderer's job precisely because they are
|
|
7703
|
+
* locale work, and this store holds keys rather than text.
|
|
7704
|
+
*/
|
|
7705
|
+
readonly disabledTipKey?: string;
|
|
7706
|
+
/** Params for {@link disabledTipKey}. */
|
|
7707
|
+
readonly disabledTipParams?: MagicBarTextParams;
|
|
7708
|
+
/**
|
|
7709
|
+
* Mirror the glyph horizontally under `dir="rtl"`.
|
|
7233
7710
|
*
|
|
7234
|
-
*
|
|
7235
|
-
*
|
|
7236
|
-
*
|
|
7711
|
+
* Most marks in {@link FLY_MAGIC_BAR_ICONS} are direction-neutral — a trash can, a gear, a
|
|
7712
|
+
* calendar grid read the same in every locale, and mirroring them would be wrong. A minority
|
|
7713
|
+
* encode a DIRECTION as their meaning: indent/outdent, promote (an up-and-right arrow), a
|
|
7714
|
+
* next/previous chevron, an export tray. Those are mirrored by every RTL desktop application
|
|
7715
|
+
* there is, and left unmirrored they point at the wrong edge of the screen in `ar` and `ur` —
|
|
7716
|
+
* three of this platform's four locales.
|
|
7717
|
+
*
|
|
7718
|
+
* Opt-in rather than automatic because no property of the geometry distinguishes the two
|
|
7719
|
+
* groups: only the publisher knows whether its arrow means "forward" (mirror) or "north-east"
|
|
7720
|
+
* (do not). Defaults to `false`, so every glyph shipped before this field existed paints exactly
|
|
7721
|
+
* as it did.
|
|
7722
|
+
*
|
|
7723
|
+
* It flips only the ICON. The button, its label and the bar's own item order already mirror
|
|
7724
|
+
* through logical CSS properties — see `magic-actions.component.scss`'s header.
|
|
7237
7725
|
*/
|
|
7238
|
-
|
|
7239
|
-
/**
|
|
7240
|
-
|
|
7241
|
-
|
|
7242
|
-
|
|
7243
|
-
|
|
7244
|
-
|
|
7245
|
-
|
|
7246
|
-
|
|
7247
|
-
|
|
7248
|
-
/**
|
|
7249
|
-
|
|
7726
|
+
readonly mirrorInRtl?: boolean;
|
|
7727
|
+
/** Tooltip override while enabled. Absent → the renderer uses `labelKey`. */
|
|
7728
|
+
readonly tipKey?: string;
|
|
7729
|
+
/** Params for {@link tipKey}. */
|
|
7730
|
+
readonly tipParams?: MagicBarTextParams;
|
|
7731
|
+
/**
|
|
7732
|
+
* Semantic colour. Default `'default'`; `'danger'` is the ONLY thing that makes
|
|
7733
|
+
* an icon red (D7), `'success'` the green completed-toggle treatment.
|
|
7734
|
+
*/
|
|
7735
|
+
readonly tone?: MagicBarTone;
|
|
7736
|
+
/** `aria-pressed` for `kind: 'toggle'`. */
|
|
7737
|
+
readonly pressed?: boolean;
|
|
7738
|
+
/** Small accent dot — a non-default filter/sort is active. */
|
|
7739
|
+
readonly badgeDot?: boolean;
|
|
7740
|
+
/**
|
|
7741
|
+
* Reserved (D5 §4 item 7). The designs carry no keyboard-shortcut affordance
|
|
7742
|
+
* anywhere; the field exists so adding one later is a renderer change rather
|
|
7743
|
+
* than a contract break. Nothing renders it today.
|
|
7744
|
+
*/
|
|
7745
|
+
readonly shortcut?: string;
|
|
7250
7746
|
}
|
|
7251
|
-
/**
|
|
7252
|
-
|
|
7253
|
-
|
|
7254
|
-
/**
|
|
7255
|
-
|
|
7256
|
-
|
|
7257
|
-
|
|
7258
|
-
|
|
7259
|
-
|
|
7260
|
-
|
|
7261
|
-
* navigable; the component never assumes `body` is present when `isDeleted`).
|
|
7262
|
-
* `canEdit` / `canDelete` / `canModerate` are pre-resolved by the host (Cerbos
|
|
7263
|
-
* decision or equivalent) — the component never evaluates authorization itself.
|
|
7264
|
-
*/
|
|
7265
|
-
interface FlyComment {
|
|
7266
|
-
id: string;
|
|
7267
|
-
authorUserId: string;
|
|
7268
|
-
authorDisplayName?: string;
|
|
7269
|
-
authorAvatarUrl?: string;
|
|
7270
|
-
parentCommentId?: string;
|
|
7271
|
-
depth: number;
|
|
7272
|
-
body: string;
|
|
7273
|
-
replyCount: number;
|
|
7274
|
-
isEdited: boolean;
|
|
7275
|
-
isDeleted: boolean;
|
|
7276
|
-
createdAt: string;
|
|
7277
|
-
updatedAt?: string;
|
|
7278
|
-
canEdit: boolean;
|
|
7279
|
-
canDelete: boolean;
|
|
7280
|
-
canModerate: boolean;
|
|
7747
|
+
/** What a publisher supplies for one action. */
|
|
7748
|
+
interface MagicBarAction extends MagicBarActionSpec {
|
|
7749
|
+
readonly menu?: MagicBarRadioMenu;
|
|
7750
|
+
/**
|
|
7751
|
+
* Invoked on activation. The argument is the DOM element the renderer painted
|
|
7752
|
+
* for this action — see {@link MagicBarActionView.run} for why it is passed and
|
|
7753
|
+
* what a publisher may do with it. Ignore it and this is the zero-argument
|
|
7754
|
+
* handler it has always been.
|
|
7755
|
+
*/
|
|
7756
|
+
readonly onSelect?: (trigger?: HTMLElement) => void;
|
|
7281
7757
|
}
|
|
7282
7758
|
/**
|
|
7283
|
-
*
|
|
7284
|
-
*
|
|
7285
|
-
*
|
|
7286
|
-
* separate {@link FlyCommentPage} instances tracked by the host.
|
|
7759
|
+
* What the shell renders. `run()` always exists and always dispatches to the
|
|
7760
|
+
* publisher's LATEST handler for this id — including after a re-publish the
|
|
7761
|
+
* registry deliberately did not propagate (see `magic-bar-projection.ts`).
|
|
7287
7762
|
*/
|
|
7288
|
-
interface
|
|
7289
|
-
|
|
7290
|
-
|
|
7291
|
-
|
|
7292
|
-
|
|
7293
|
-
|
|
7294
|
-
|
|
7295
|
-
|
|
7296
|
-
|
|
7297
|
-
|
|
7298
|
-
|
|
7299
|
-
|
|
7300
|
-
|
|
7301
|
-
|
|
7302
|
-
|
|
7303
|
-
|
|
7304
|
-
|
|
7305
|
-
|
|
7306
|
-
|
|
7307
|
-
|
|
7308
|
-
|
|
7309
|
-
|
|
7310
|
-
|
|
7311
|
-
|
|
7312
|
-
|
|
7313
|
-
|
|
7763
|
+
interface MagicBarActionView extends MagicBarActionSpec {
|
|
7764
|
+
readonly menu: MagicBarRadioMenuView | null;
|
|
7765
|
+
/**
|
|
7766
|
+
* Fire the publisher's newest handler for this id.
|
|
7767
|
+
*
|
|
7768
|
+
* ## Why it carries the trigger element
|
|
7769
|
+
* An action that opens a POPOVER the publisher owns — the canonical case is a
|
|
7770
|
+
* listing screen's advanced-filter panel — has to position that popover under
|
|
7771
|
+
* the button the user just pressed. The publisher cannot find that button:
|
|
7772
|
+
* embedded, it is painted by `fly-magic-actions` inside the shell's top-bar
|
|
7773
|
+
* pill, in the shell's DOM, several stacking contexts and one federation
|
|
7774
|
+
* boundary away from the remote that published the action. Before this argument
|
|
7775
|
+
* existed, PPM's projects register had to anchor its panel to its own page
|
|
7776
|
+
* header instead, which put the panel in the middle of the window while the
|
|
7777
|
+
* button that opened it sat in the chrome above — an affordance with no visible
|
|
7778
|
+
* relationship to its own trigger.
|
|
7779
|
+
*
|
|
7780
|
+
* Passing the element rather than modelling the popover is deliberate. The
|
|
7781
|
+
* panel's CONTENT is app schema (see {@link MagicBarSearch.onOpenFilters} for
|
|
7782
|
+
* the same ruling), so it must stay in the publisher's own DOM and injection
|
|
7783
|
+
* context; only its POSITION is chrome-relative. An element reference crosses
|
|
7784
|
+
* the federation boundary without any of the coupling a descriptor would need —
|
|
7785
|
+
* a DOM node is a DOM node in every bundle. `fly-filter-panel`'s `[anchorEl]`
|
|
7786
|
+
* is the intended consumer.
|
|
7787
|
+
*
|
|
7788
|
+
* ## What a publisher must not assume
|
|
7789
|
+
* The element is the trigger AS PAINTED RIGHT NOW. It is valid for the duration
|
|
7790
|
+
* of the popover, not beyond: a re-publish that drops this action id destroys it
|
|
7791
|
+
* (`@for (…; track action.id)`), and a mode switch repaints it in a different
|
|
7792
|
+
* chrome entirely. Hold it in a signal the popover's open-state clears, never in
|
|
7793
|
+
* long-lived state, and never mutate it.
|
|
7794
|
+
*
|
|
7795
|
+
* It is OPTIONAL because not every renderer has one to give — a keyboard-driven
|
|
7796
|
+
* invocation, a synthetic call in a test, an inline composer that paints no
|
|
7797
|
+
* button. A publisher that receives `undefined` must still work: for a popover
|
|
7798
|
+
* that means falling back to its own in-page anchoring, which is exactly what
|
|
7799
|
+
* `fly-filter-panel` does when `[anchorEl]` is null.
|
|
7800
|
+
*/
|
|
7801
|
+
run(trigger?: HTMLElement): void;
|
|
7314
7802
|
}
|
|
7315
|
-
/**
|
|
7316
|
-
interface
|
|
7317
|
-
|
|
7803
|
+
/** Render surface of a group — the dedupe key for {@link MagicBarGroup}. */
|
|
7804
|
+
interface MagicBarGroupSpec {
|
|
7805
|
+
readonly id: string;
|
|
7806
|
+
/** i18n key for the `role="group"` aria-label ("Signal actions"). */
|
|
7807
|
+
readonly labelKey: string;
|
|
7808
|
+
/** Framed variant: 2 px gaps + a trailing separator. Plain (default) uses 8 px gaps. */
|
|
7809
|
+
readonly framed?: boolean;
|
|
7318
7810
|
}
|
|
7319
|
-
|
|
7320
|
-
|
|
7321
|
-
commentId: string;
|
|
7322
|
-
reason: FlyCommentReportReason;
|
|
7323
|
-
detail?: string;
|
|
7811
|
+
interface MagicBarGroup extends MagicBarGroupSpec {
|
|
7812
|
+
readonly items: readonly MagicBarAction[];
|
|
7324
7813
|
}
|
|
7325
|
-
|
|
7326
|
-
|
|
7327
|
-
locked: boolean;
|
|
7814
|
+
interface MagicBarGroupView extends MagicBarGroupSpec {
|
|
7815
|
+
readonly items: readonly MagicBarActionView[];
|
|
7328
7816
|
}
|
|
7329
|
-
|
|
7330
7817
|
/**
|
|
7331
|
-
*
|
|
7332
|
-
*
|
|
7333
|
-
* Renders a {@link FlyCommentPage} (root comments) plus lazily-fetched nested
|
|
7334
|
-
* reply pages into an accessible, theme-aware thread: reply composer, inline
|
|
7335
|
-
* edit, soft-delete (tombstone render), typed report-with-reason dialog, and
|
|
7336
|
-
* moderator affordances (lock/unlock, delete-any). It is a platform surface —
|
|
7337
|
-
* transport-agnostic like `fly-survey-form` / `fly-dynamic-form`: this component
|
|
7338
|
-
* never calls an API. It only renders the pages the host hands it via
|
|
7339
|
-
* `[rootPage]` / `[repliesByParent]` and emits typed requests
|
|
7340
|
-
* (`loadReplies`/`loadMore`/`submit`/`edit`/`delete`/`report`/`lockToggle`) —
|
|
7341
|
-
* the host owns HTTP, optimistic-insert reconciliation, and any live-update
|
|
7342
|
-
* channel (SignalR, polling, …).
|
|
7343
|
-
*
|
|
7344
|
-
* Nested replies are fetched **lazily on expand** (`loadReplies`, never an
|
|
7345
|
-
* eager load-all) — the explicit fix for the legacy unpaged-children scale bug
|
|
7346
|
-
* — and each level pages independently via `loadMore`.
|
|
7347
|
-
*
|
|
7348
|
-
* The `comments` core app owns no user profile data, so `FlyComment` carries
|
|
7349
|
-
* `authorUserId` and an OPTIONAL `authorDisplayName`. Rather than make every host
|
|
7350
|
-
* map names in itself (and render GUIDs when it forgets), bind
|
|
7351
|
-
* `[resolveDisplayName]` to `FlyUserDirectoryService.label` — see
|
|
7352
|
-
* {@link FlyCommentThreadComponent.resolveDisplayName}. Still transport-agnostic:
|
|
7353
|
-
* the resolver is a function the host hands over, not a call this component makes.
|
|
7354
|
-
*
|
|
7355
|
-
* i18n is self-sufficient through the `comment.*` keys in `DS_BASELINE_LOCALES`
|
|
7356
|
-
* (en/ar/fr/ur), overridable by any consumer key of the same name. RTL works via
|
|
7357
|
-
* logical CSS. Styling uses DS theme tokens (`--surface-*`, `--label-*`,
|
|
7358
|
-
* `--separator`, `--fill-*`, `--accent`, `--system-*`) with light-neutral
|
|
7359
|
-
* fallbacks so it stays readable even in a consumer that hasn't mapped them.
|
|
7818
|
+
* Render surface of the expanding search field — the dedupe key for
|
|
7819
|
+
* {@link MagicBarSearch}.
|
|
7360
7820
|
*
|
|
7361
|
-
*
|
|
7362
|
-
*
|
|
7363
|
-
* <fly-comment-thread
|
|
7364
|
-
* [rootPage]="rootPage()"
|
|
7365
|
-
* [repliesByParent]="repliesByParent()"
|
|
7366
|
-
* [currentUserId]="me.id"
|
|
7367
|
-
* [resolveDisplayName]="directory.label"
|
|
7368
|
-
* [canModerateThread]="canModerate()"
|
|
7369
|
-
* [isLocked]="thread().isLocked"
|
|
7370
|
-
* (loadReplies)="onLoadReplies($event)"
|
|
7371
|
-
* (loadMore)="onLoadMore($event)"
|
|
7372
|
-
* (submit)="onSubmit($event)"
|
|
7373
|
-
* (edit)="onEdit($event)"
|
|
7374
|
-
* (delete)="onDelete($event)"
|
|
7375
|
-
* (report)="onReport($event)"
|
|
7376
|
-
* (lockToggle)="onLockToggle($event)" />
|
|
7377
|
-
* ```
|
|
7821
|
+
* This is a per-page typeahead, NOT a command palette: neither design package
|
|
7822
|
+
* has a global ⌘K surface, and the only "command" affordance is the Ask-AI menu.
|
|
7378
7823
|
*/
|
|
7379
|
-
|
|
7380
|
-
/**
|
|
7381
|
-
readonly
|
|
7382
|
-
/**
|
|
7383
|
-
|
|
7384
|
-
* accumulated across `loadMore` calls by the host. Additive to the frozen
|
|
7385
|
-
* contract's `rootPage` input — required because a lazily-nested tree has no
|
|
7386
|
-
* other channel to carry fetched reply data back into the component.
|
|
7387
|
-
*/
|
|
7388
|
-
readonly repliesByParent: _angular_core.InputSignal<Readonly<Record<string, FlyCommentPage>>>;
|
|
7389
|
-
/** Current sort order label (host owns re-fetch on {@link sortChange}; purely descriptive here otherwise). */
|
|
7390
|
-
readonly sort: _angular_core.InputSignal<"newest" | "oldest">;
|
|
7391
|
-
/** Locked threads disable the composer (root + reply) entirely, for every user. */
|
|
7392
|
-
readonly isLocked: _angular_core.InputSignal<boolean>;
|
|
7393
|
-
/** The signed-in user's id — gates the "report" affordance (can't report your own comment). */
|
|
7394
|
-
readonly currentUserId: _angular_core.InputSignal<string | null>;
|
|
7395
|
-
/** Replay / read-only mode — hides composer, reply, edit, delete, report, and lock affordances.
|
|
7396
|
-
* Aliased to `[readonly]` (the public binding); the class member avoids shadowing the
|
|
7397
|
-
* TypeScript `readonly` keyword. */
|
|
7398
|
-
readonly isReadonly: _angular_core.InputSignal<boolean>;
|
|
7399
|
-
/** Thread-scoped moderator permission (lock/unlock). Additive — distinct from the
|
|
7400
|
-
* per-comment `canModerate` flag, which gates delete-any on that specific comment. */
|
|
7401
|
-
readonly canModerateThread: _angular_core.InputSignal<boolean>;
|
|
7824
|
+
interface MagicBarSearchSpec {
|
|
7825
|
+
/** Context-aware placeholder key ("Search tasks…", "Search events…"). */
|
|
7826
|
+
readonly placeholderKey: string;
|
|
7827
|
+
/** Params for {@link placeholderKey}, e.g. `{ count: 1204 }` for "Search {{count}} tasks…". */
|
|
7828
|
+
readonly placeholderParams?: MagicBarTextParams;
|
|
7402
7829
|
/**
|
|
7403
|
-
*
|
|
7404
|
-
*
|
|
7405
|
-
* this every host had to map display names into `authorDisplayName` itself — and
|
|
7406
|
-
* a host that forgot rendered raw GUIDs at the reader.
|
|
7830
|
+
* The text the search field should SHOW — literal text, not an i18n key, because
|
|
7831
|
+
* it is the user's own query rather than a caption.
|
|
7407
7832
|
*
|
|
7408
|
-
*
|
|
7409
|
-
*
|
|
7410
|
-
*
|
|
7411
|
-
*
|
|
7833
|
+
* Exists because a view can arrive **already filtered**: a deep link carrying
|
|
7834
|
+
* `?q=…`, a restored session, a filter applied from a detail pane. Without it the
|
|
7835
|
+
* box renders empty over a visibly filtered list, and the user is looking at a
|
|
7836
|
+
* contradiction the chrome cannot explain.
|
|
7412
7837
|
*
|
|
7413
|
-
*
|
|
7414
|
-
*
|
|
7415
|
-
*
|
|
7416
|
-
*
|
|
7417
|
-
|
|
7418
|
-
|
|
7419
|
-
|
|
7420
|
-
|
|
7421
|
-
|
|
7422
|
-
|
|
7423
|
-
|
|
7424
|
-
|
|
7425
|
-
|
|
7426
|
-
|
|
7427
|
-
|
|
7428
|
-
|
|
7429
|
-
|
|
7430
|
-
|
|
7431
|
-
|
|
7432
|
-
|
|
7433
|
-
|
|
7434
|
-
|
|
7435
|
-
|
|
7436
|
-
|
|
7437
|
-
|
|
7438
|
-
|
|
7439
|
-
|
|
7440
|
-
|
|
7441
|
-
|
|
7442
|
-
|
|
7443
|
-
|
|
7444
|
-
|
|
7445
|
-
|
|
7446
|
-
|
|
7447
|
-
|
|
7448
|
-
|
|
7449
|
-
|
|
7450
|
-
|
|
7451
|
-
|
|
7452
|
-
|
|
7453
|
-
|
|
7454
|
-
readonly
|
|
7455
|
-
private readonly _base;
|
|
7456
|
-
readonly reportReasons: readonly FlyCommentReportReason[];
|
|
7457
|
-
/** commentIds whose reply subtree is currently expanded/visible. */
|
|
7458
|
-
private readonly _expanded;
|
|
7459
|
-
/** Composer draft text, keyed by parentCommentId (root uses {@link ROOT_DRAFT_KEY}). */
|
|
7460
|
-
private readonly _drafts;
|
|
7461
|
-
/** commentIds whose reply composer box is currently open (distinct from `_expanded`, which toggles the read view). */
|
|
7462
|
-
private readonly _replyBoxOpen;
|
|
7463
|
-
private readonly _editingId;
|
|
7464
|
-
private readonly _editDraft;
|
|
7465
|
-
private readonly _confirmingDeleteId;
|
|
7466
|
-
private readonly _reportingId;
|
|
7467
|
-
private readonly _reportReason;
|
|
7468
|
-
private readonly _reportDetail;
|
|
7469
|
-
readonly rootDraft: _angular_core.Signal<string>;
|
|
7470
|
-
readonly editingId: _angular_core.Signal<string | null>;
|
|
7471
|
-
readonly confirmingDeleteId: _angular_core.Signal<string | null>;
|
|
7472
|
-
readonly reportingId: _angular_core.Signal<string | null>;
|
|
7473
|
-
readonly reportReason: _angular_core.Signal<FlyCommentReportReason | null>;
|
|
7474
|
-
readonly reportDetail: _angular_core.Signal<string>;
|
|
7475
|
-
fieldId(suffix: string): string;
|
|
7476
|
-
isExpanded(commentId: string): boolean;
|
|
7477
|
-
isReplyBoxOpen(commentId: string): boolean;
|
|
7478
|
-
repliesFor(commentId: string): FlyCommentPage | undefined;
|
|
7479
|
-
replyDraft(commentId: string): string;
|
|
7480
|
-
isOwn(comment: FlyComment): boolean;
|
|
7838
|
+
* ## Why it is not called `query`
|
|
7839
|
+
* {@link MagicBarSearchView} — which extends this interface — already declares
|
|
7840
|
+
* `query(text: string): void`, the late-bound invoker. A `query?: string` here
|
|
7841
|
+
* would make that view an illegal extension (TS2430: `(text: string) => void` is
|
|
7842
|
+
* not assignable to `string | undefined`), and the only other way out — renaming
|
|
7843
|
+
* the invoker — removes a member of a shipped exported interface, which is a
|
|
7844
|
+
* ds-compat MAJOR (rule 7) and forks the federation singleton for every remote.
|
|
7845
|
+
* So the field takes the name that pairs with the invoker instead of colliding
|
|
7846
|
+
* with it: `queryText` is the text, `query()` submits it.
|
|
7847
|
+
*
|
|
7848
|
+
* ## Precedence — this is a SEED, not a controlled value
|
|
7849
|
+
* The field's live text is owned by the **shell**, because the user types into
|
|
7850
|
+
* it. This field is the publisher's chance to move it, and the shell adopts the
|
|
7851
|
+
* published value exactly three times:
|
|
7852
|
+
*
|
|
7853
|
+
* 1. the first time it binds this view,
|
|
7854
|
+
* 2. when {@link MagicBarContribution.viewKey} changes (reset-on-navigate — the
|
|
7855
|
+
* previous view's query must not survive into the next one), and
|
|
7856
|
+
* 3. when the published value **itself changes** from the one previously
|
|
7857
|
+
* published.
|
|
7858
|
+
*
|
|
7859
|
+
* A re-publish carrying an UNCHANGED `queryText` never touches what the user has
|
|
7860
|
+
* typed. That third clause is the whole rule: the dominant re-publish is
|
|
7861
|
+
* `disabled: !hasSelection` flipping on a selection change, and a shell that
|
|
7862
|
+
* re-read `queryText` on every emitted view would revert a keystroke every time
|
|
7863
|
+
* the user selected a row mid-search — the classic controlled-input bug. The rule
|
|
7864
|
+
* is authored once, as {@link magicBarSearchText}, so no renderer re-derives it.
|
|
7865
|
+
*
|
|
7866
|
+
* `undefined` and `''` are **different** and the difference is load-bearing:
|
|
7867
|
+
* absent means "this view does not manage the field" (nothing is ever forced),
|
|
7868
|
+
* `''` means "clear it". Both the fingerprint and the seed comparison distinguish
|
|
7869
|
+
* them.
|
|
7870
|
+
*
|
|
7871
|
+
* ## Do not echo the user's keystrokes back through this field
|
|
7872
|
+
* A publisher that mirrors its `onQuery` argument straight back into `queryText`
|
|
7873
|
+
* is harmless (the seed changes to text the field already shows). A publisher
|
|
7874
|
+
* that mirrors it back **debounced** is not: typing "abc" then publishing
|
|
7875
|
+
* `queryText: 'a'` 300 ms later is, by rule 3, a genuine publisher-initiated
|
|
7876
|
+
* change, and the field snaps back to "a". Publish here only for state the view
|
|
7877
|
+
* owns independently of the field.
|
|
7878
|
+
*/
|
|
7879
|
+
readonly queryText?: string;
|
|
7481
7880
|
/**
|
|
7482
|
-
*
|
|
7483
|
-
* explicit `authorDisplayName` (a host that already knows the name, or a
|
|
7484
|
-
* backend that returns one, always wins) → {@link resolveDisplayName} →
|
|
7485
|
-
* the raw `authorUserId`.
|
|
7881
|
+
* Expanded width in px — a **desktop layout hint**, carried verbatim.
|
|
7486
7882
|
*
|
|
7487
|
-
* The
|
|
7488
|
-
*
|
|
7489
|
-
*
|
|
7883
|
+
* The design's range is 140–420 (default 230), but this store deliberately does
|
|
7884
|
+
* NOT validate or clamp it: enforcing a paint range here would reject a whole
|
|
7885
|
+
* contribution over a cosmetic hint (leaving the previous view's actions in the
|
|
7886
|
+
* chrome), and mobile ignores the field entirely, so there is no single range to
|
|
7887
|
+
* enforce. `fly-magic-actions` clamps to the design range at paint time and is
|
|
7888
|
+
* the only place that decides what an out-of-range or non-finite value means.
|
|
7490
7889
|
*/
|
|
7491
|
-
|
|
7492
|
-
/**
|
|
7493
|
-
|
|
7494
|
-
canReport(comment: FlyComment): boolean;
|
|
7495
|
-
canReply(): boolean;
|
|
7496
|
-
canDeleteComment(comment: FlyComment): boolean;
|
|
7497
|
-
canEditComment(comment: FlyComment): boolean;
|
|
7498
|
-
formatDate(iso: string): string;
|
|
7499
|
-
onRootDraftChange(value: string): void;
|
|
7500
|
-
submitRoot(): void;
|
|
7501
|
-
toggleReplies(comment: FlyComment): void;
|
|
7502
|
-
private _expand;
|
|
7503
|
-
loadMoreRoot(): void;
|
|
7504
|
-
loadMoreReplies(parentId: string): void;
|
|
7505
|
-
openReplyBox(commentId: string): void;
|
|
7506
|
-
closeReplyBox(commentId: string): void;
|
|
7507
|
-
onReplyDraftChange(commentId: string, value: string): void;
|
|
7508
|
-
submitReply(commentId: string): void;
|
|
7509
|
-
startEdit(comment: FlyComment): void;
|
|
7510
|
-
onEditDraftChange(value: string): void;
|
|
7511
|
-
saveEdit(comment: FlyComment): void;
|
|
7512
|
-
cancelEdit(): void;
|
|
7513
|
-
requestDelete(comment: FlyComment): void;
|
|
7514
|
-
confirmDelete(comment: FlyComment): void;
|
|
7515
|
-
cancelDelete(): void;
|
|
7516
|
-
openReport(comment: FlyComment): void;
|
|
7517
|
-
onReportReasonChange(reason: FlyCommentReportReason): void;
|
|
7518
|
-
onReportDetailChange(value: string): void;
|
|
7519
|
-
submitReport(): void;
|
|
7520
|
-
closeReport(): void;
|
|
7521
|
-
/** Space would otherwise scroll the page while the backdrop (role="button") is focused. */
|
|
7522
|
-
onOverlayBackdropSpace(event: Event): void;
|
|
7523
|
-
toggleLock(): void;
|
|
7524
|
-
onSortPick(next: 'newest' | 'oldest'): void;
|
|
7525
|
-
private _setDraft;
|
|
7526
|
-
static ɵfac: _angular_core.ɵɵFactoryDeclaration<FlyCommentThreadComponent, never>;
|
|
7527
|
-
static ɵcmp: _angular_core.ɵɵComponentDeclaration<FlyCommentThreadComponent, "fly-comment-thread", never, { "rootPage": { "alias": "rootPage"; "required": true; "isSignal": true; }; "repliesByParent": { "alias": "repliesByParent"; "required": false; "isSignal": true; }; "sort": { "alias": "sort"; "required": false; "isSignal": true; }; "isLocked": { "alias": "isLocked"; "required": false; "isSignal": true; }; "currentUserId": { "alias": "currentUserId"; "required": false; "isSignal": true; }; "isReadonly": { "alias": "readonly"; "required": false; "isSignal": true; }; "canModerateThread": { "alias": "canModerateThread"; "required": false; "isSignal": true; }; "resolveDisplayName": { "alias": "resolveDisplayName"; "required": false; "isSignal": true; }; }, { "loadReplies": "loadReplies"; "loadMore": "loadMore"; "submit": "submit"; "edit": "edit"; "delete": "delete"; "report": "report"; "lockToggle": "lockToggle"; "sortChange": "sortChange"; }, never, never, true, never>;
|
|
7890
|
+
readonly openWidth?: number;
|
|
7891
|
+
/** Accent dot on the Filters button — a non-default filter is applied. */
|
|
7892
|
+
readonly filtersActive?: boolean;
|
|
7528
7893
|
}
|
|
7529
|
-
|
|
7530
|
-
|
|
7531
|
-
|
|
7532
|
-
|
|
7533
|
-
|
|
7534
|
-
|
|
7535
|
-
|
|
7536
|
-
|
|
7537
|
-
|
|
7538
|
-
|
|
7539
|
-
challenge: string;
|
|
7540
|
-
/** Base64 random salt, unique per challenge. */
|
|
7541
|
-
salt: string;
|
|
7542
|
-
/** HMAC signature binding challenge + maxNumber + expiresAt (server-verified). */
|
|
7543
|
-
signature: string;
|
|
7544
|
-
/** Exclusive upper bound of the search space (difficulty). */
|
|
7545
|
-
maxNumber: number;
|
|
7546
|
-
/** ISO-8601 instant after which the solution is rejected. Echoed back verbatim. */
|
|
7547
|
-
expiresAt: string;
|
|
7894
|
+
interface MagicBarSearch extends MagicBarSearchSpec {
|
|
7895
|
+
readonly onQuery?: (query: string) => void;
|
|
7896
|
+
/**
|
|
7897
|
+
* Opens the view's own Advanced-search overlay. Presence of this handler is
|
|
7898
|
+
* what makes the Filters button exist — the DS deliberately does not model the
|
|
7899
|
+
* dialog itself. Its fields are app schema (Circles' PESTLE/horizon grid), and
|
|
7900
|
+
* a descriptor for them would be business logic the design system cannot
|
|
7901
|
+
* validate or render honestly.
|
|
7902
|
+
*/
|
|
7903
|
+
readonly onOpenFilters?: (trigger?: HTMLElement) => void;
|
|
7548
7904
|
}
|
|
7549
|
-
|
|
7550
|
-
|
|
7551
|
-
|
|
7552
|
-
|
|
7553
|
-
|
|
7554
|
-
|
|
7555
|
-
|
|
7556
|
-
|
|
7557
|
-
|
|
7558
|
-
|
|
7559
|
-
|
|
7560
|
-
|
|
7561
|
-
|
|
7562
|
-
|
|
7563
|
-
|
|
7905
|
+
interface MagicBarSearchView extends MagicBarSearchSpec {
|
|
7906
|
+
/** True iff the publisher can open an advanced-search overlay. */
|
|
7907
|
+
readonly hasFilters: boolean;
|
|
7908
|
+
/**
|
|
7909
|
+
* Submit the field's current text to the publisher's newest `onQuery`. The
|
|
7910
|
+
* inbound half — what the field should SHOW — is
|
|
7911
|
+
* {@link MagicBarSearchSpec.queryText}, and that asymmetry in naming is forced:
|
|
7912
|
+
* this member shipped first, and renaming it would be a ds-compat MAJOR.
|
|
7913
|
+
*/
|
|
7914
|
+
query(text: string): void;
|
|
7915
|
+
/**
|
|
7916
|
+
* Open the publisher's advanced-search overlay. Carries the Filters button the
|
|
7917
|
+
* shell painted, for the same reason and under the same caveats as
|
|
7918
|
+
* {@link MagicBarActionView.run} — a publisher whose overlay is a popover
|
|
7919
|
+
* anchors it there instead of guessing at a position inside its own page.
|
|
7920
|
+
*/
|
|
7921
|
+
openFilters(trigger?: HTMLElement): void;
|
|
7564
7922
|
}
|
|
7565
|
-
/** The solver lifecycle surfaced by the component's `state()` signal. */
|
|
7566
|
-
type FlyCaptchaState = 'idle' | 'verifying' | 'verified' | 'expired' | 'error';
|
|
7567
|
-
|
|
7568
|
-
/** Lowercase-hex SHA-256 of `input` via Web Crypto — matches `Convert.ToHexStringLower(SHA256…)`. */
|
|
7569
|
-
declare function flyCaptchaSha256Hex(input: string): Promise<string>;
|
|
7570
|
-
/** Standard base64 of the UTF-8 bytes of `s` — matches .NET `Convert.ToBase64String`. */
|
|
7571
|
-
declare function flyCaptchaBase64Utf8(s: string): string;
|
|
7572
7923
|
/**
|
|
7573
|
-
*
|
|
7574
|
-
*
|
|
7575
|
-
*
|
|
7924
|
+
* One view's complete claim on the magic bar.
|
|
7925
|
+
*
|
|
7926
|
+
* Identity (`appId` / `windowId`) is deliberately absent: it belongs to the
|
|
7927
|
+
* {@link MagicBarPublisher} that was minted for this owner, so a later publish
|
|
7928
|
+
* cannot re-target another app's slot.
|
|
7576
7929
|
*/
|
|
7577
|
-
|
|
7930
|
+
interface MagicBarContribution {
|
|
7931
|
+
/**
|
|
7932
|
+
* What the publisher is showing, e.g. `'tasks:detail'`. A change here is
|
|
7933
|
+
* reset-on-navigate: the registry replaces the slot wholesale rather than
|
|
7934
|
+
* reconciling, so nothing from the previous view can survive.
|
|
7935
|
+
*/
|
|
7936
|
+
readonly viewKey: string;
|
|
7937
|
+
readonly search?: MagicBarSearch | null;
|
|
7938
|
+
/** Ordered clusters, separator-joined. */
|
|
7939
|
+
readonly groups?: readonly MagicBarGroup[];
|
|
7940
|
+
/** The accent-filled CTA ("New task", "Add signal"). */
|
|
7941
|
+
readonly primary?: MagicBarAction | null;
|
|
7942
|
+
/**
|
|
7943
|
+
* Ids of {@link AgentCommand}s this view considers most relevant, most-relevant
|
|
7944
|
+
* first — the Ask-AI menu's per-view sets.
|
|
7945
|
+
*
|
|
7946
|
+
* Ids, not command objects: the platform already models commands (manifest
|
|
7947
|
+
* `commands[]` → `AgentCommandRegistry`), and D5 §6 item 9 is explicit that
|
|
7948
|
+
* production must source these from manifests instead of the mock's hardcoded
|
|
7949
|
+
* `{ title, note, prompt }` triples. Duplicating that model here would fork the
|
|
7950
|
+
* palette and reintroduce hardcoded prompt text. Unknown ids are dropped by the
|
|
7951
|
+
* resolver; an empty list leaves the shell's affinity ranking in charge.
|
|
7952
|
+
*/
|
|
7953
|
+
readonly quickCommandIds?: readonly string[];
|
|
7954
|
+
/** The "…" overflow set. Reserved design intent (D5 §6 item 8) — Print / Export / Settings. */
|
|
7955
|
+
readonly overflow?: readonly MagicBarAction[];
|
|
7956
|
+
}
|
|
7957
|
+
/** The shell-facing projection of a contribution. See `magic-bar-projection.ts`. */
|
|
7958
|
+
interface MagicBarView {
|
|
7959
|
+
readonly appId: string;
|
|
7960
|
+
readonly windowId?: string;
|
|
7961
|
+
/** {@link magicBarOwnerKey} of the publisher. */
|
|
7962
|
+
readonly ownerKey: string;
|
|
7963
|
+
readonly viewKey: string;
|
|
7964
|
+
readonly search: MagicBarSearchView | null;
|
|
7965
|
+
readonly groups: readonly MagicBarGroupView[];
|
|
7966
|
+
readonly primary: MagicBarActionView | null;
|
|
7967
|
+
readonly quickCommandIds: readonly string[];
|
|
7968
|
+
readonly overflow: readonly MagicBarActionView[];
|
|
7969
|
+
}
|
|
7578
7970
|
/**
|
|
7579
|
-
*
|
|
7580
|
-
*
|
|
7581
|
-
*
|
|
7582
|
-
*
|
|
7583
|
-
*
|
|
7584
|
-
*
|
|
7585
|
-
* hashes candidates with a vendored **synchronous** SHA-256 ({@link sha256HexSync}
|
|
7586
|
-
* from `./sha256` — no `crypto.subtle`/promise overhead per candidate, which used
|
|
7587
|
-
* to dominate solve time), in chunks scheduled on `requestAnimationFrame` so a
|
|
7588
|
-
* chunk boundary still yields back to the browser between slices. It auto-starts
|
|
7589
|
-
* whenever the `[challenge]` input changes. Implements
|
|
7590
|
-
* {@link ControlValueAccessor} so it drops into a reactive form / `[(ngModel)]` —
|
|
7591
|
-
* the control value IS the token string.
|
|
7592
|
-
*
|
|
7593
|
-
* Expiry is the host's concern to refresh: the component checks `expiresAt` up
|
|
7594
|
-
* front and while solving, emits {@link expired}, and stops. i18n is
|
|
7595
|
-
* self-sufficient via the `captcha.*` baseline keys; RTL works via logical CSS.
|
|
7596
|
-
*
|
|
7597
|
-
* @example
|
|
7598
|
-
* ```html
|
|
7599
|
-
* <fly-captcha [challenge]="challenge()" (solved)="post($event)" (expired)="refresh()" />
|
|
7600
|
-
* ```
|
|
7971
|
+
* A view's handle on its magic-bar slot. Minted once per publisher (not per
|
|
7972
|
+
* publish) because the publish rate is the whole point of this surface: the
|
|
7973
|
+
* sibling registries hand back a handle per `register()` and expect a handful of
|
|
7974
|
+
* calls per app lifetime, whereas a magic-bar publisher re-emits on every
|
|
7975
|
+
* selection change. Handing out a fresh handle each time would leave the caller
|
|
7976
|
+
* holding a dead one and force it to reassign on every keystroke.
|
|
7601
7977
|
*/
|
|
7602
|
-
|
|
7603
|
-
|
|
7604
|
-
readonly challenge: _angular_core.InputSignal<FlyCaptchaChallenge | null>;
|
|
7605
|
-
/** Candidates hashed synchronously in one slice before yielding back to the browser
|
|
7606
|
-
* on the next animation frame. Higher = fewer `requestAnimationFrame` hops (each
|
|
7607
|
-
* carries ~16ms of frame-boundary overhead), more synchronous work per slice.
|
|
7608
|
-
* 20,000 keeps a slice's own hashing time well under a long-task budget on modern
|
|
7609
|
-
* hardware (the vendored sync SHA-256 does several hundred thousand hashes/sec)
|
|
7610
|
-
* while needing only a handful of hops to clear the library's default difficulty. */
|
|
7611
|
-
readonly chunkSize: _angular_core.InputSignal<number>;
|
|
7612
|
-
/** The solution token once solved — the exact string to POST back to the backend. */
|
|
7613
|
-
readonly solved: _angular_core.OutputEmitterRef<string>;
|
|
7614
|
-
/** The challenge expired (up-front or mid-solve). The host should request a new one. */
|
|
7615
|
-
readonly expired: _angular_core.OutputEmitterRef<void>;
|
|
7616
|
-
readonly state: _angular_core.WritableSignal<FlyCaptchaState>;
|
|
7617
|
-
readonly token: _angular_core.WritableSignal<string | null>;
|
|
7618
|
-
/** Monotonic generation — bumped on every restart/destroy so a stale async chunk
|
|
7619
|
-
* or timer that captured an older generation no-ops instead of racing. */
|
|
7620
|
-
private _gen;
|
|
7621
|
-
private _raf;
|
|
7622
|
-
private _expiryTimer;
|
|
7623
|
-
private _onChange;
|
|
7624
|
-
private _onTouched;
|
|
7625
|
-
constructor();
|
|
7626
|
-
ngOnDestroy(): void;
|
|
7627
|
-
private _restart;
|
|
7978
|
+
interface MagicBarPublisher {
|
|
7979
|
+
readonly owner: MagicBarOwnerRef;
|
|
7628
7980
|
/**
|
|
7629
|
-
*
|
|
7630
|
-
*
|
|
7631
|
-
*
|
|
7632
|
-
*
|
|
7633
|
-
*
|
|
7634
|
-
*
|
|
7981
|
+
* Replace this owner's contribution. No-op after {@link dispose}, and no-op
|
|
7982
|
+
* after the shell has {@link MagicBarRegistry.clear}ed this owner key.
|
|
7983
|
+
*
|
|
7984
|
+
* **Publish is last-writer-wins and eviction is not** — a deliberate asymmetry.
|
|
7985
|
+
* A stale publisher (one that has been replaced on this key by a newer one)
|
|
7986
|
+
* cannot `dispose()` the newer one out of the slot, but it *can* still take the
|
|
7987
|
+
* slot back by publishing. Symmetry would need a "newest publisher wins" rule
|
|
7988
|
+
* enforced on write, which would make the first publish of a replacement
|
|
7989
|
+
* publisher silently drop whenever two live views briefly share a key. The
|
|
7990
|
+
* exposure is bounded: two live publishers on one owner key only happen while a
|
|
7991
|
+
* view is being replaced in place, and the loser re-publishes on its next
|
|
7992
|
+
* selection change. The unbounded case — a publisher that outlives its window —
|
|
7993
|
+
* is closed by `clear()`'s tombstone, not by write ordering.
|
|
7994
|
+
*/
|
|
7995
|
+
publish(contribution: MagicBarContribution): void;
|
|
7996
|
+
/**
|
|
7997
|
+
* Release the slot. Idempotent, and a no-op if another publisher has since
|
|
7998
|
+
* taken this owner key — the same stale-handle rule the sibling registries use.
|
|
7635
7999
|
*/
|
|
7636
|
-
|
|
7637
|
-
private _onSolved;
|
|
7638
|
-
private _cancel;
|
|
7639
|
-
private _schedule;
|
|
7640
|
-
private _cancelSchedule;
|
|
7641
|
-
writeValue(value: string | null): void;
|
|
7642
|
-
registerOnChange(fn: (v: string | null) => void): void;
|
|
7643
|
-
registerOnTouched(fn: () => void): void;
|
|
7644
|
-
static ɵfac: _angular_core.ɵɵFactoryDeclaration<FlyCaptchaComponent, never>;
|
|
7645
|
-
static ɵcmp: _angular_core.ɵɵComponentDeclaration<FlyCaptchaComponent, "fly-captcha", never, { "challenge": { "alias": "challenge"; "required": false; "isSignal": true; }; "chunkSize": { "alias": "chunkSize"; "required": false; "isSignal": true; }; }, { "solved": "solved"; "expired": "expired"; }, never, never, true, never>;
|
|
8000
|
+
dispose(): void;
|
|
7646
8001
|
}
|
|
7647
8002
|
|
|
7648
8003
|
/**
|
|
7649
|
-
*
|
|
8004
|
+
* The Gantt **Period** control as a magic-bar radio-menu item.
|
|
7650
8005
|
*
|
|
7651
|
-
*
|
|
7652
|
-
*
|
|
7653
|
-
*
|
|
8006
|
+
* ## Why it is called Period and not Zoom
|
|
8007
|
+
* The control does not scale the chart — it changes the unit the time axis is measured in
|
|
8008
|
+
* (day / week / month / quarter), which is what a planner calls the *period*. "Zoom" invites the
|
|
8009
|
+
* browser's own Ctrl+wheel meaning, which this chart deliberately remaps to horizontal scrolling
|
|
8010
|
+
* (`gantt-pan.ts`), so two different verbs would have shared one word on the same surface. The
|
|
8011
|
+
* underlying type stays {@link GanttZoom} — renaming a shipped exported type is MAJOR under
|
|
8012
|
+
* `tools/ds-compat` and would fork the federation singleton for every remote over a caption.
|
|
7654
8013
|
*
|
|
7655
|
-
*
|
|
7656
|
-
*
|
|
7657
|
-
*
|
|
7658
|
-
*
|
|
7659
|
-
*
|
|
7660
|
-
*
|
|
8014
|
+
* ## Why it lives in the design system
|
|
8015
|
+
* A period picker is not app vocabulary: every screen that draws a `fly-gantt` needs exactly these
|
|
8016
|
+
* four levels under exactly these labels, and the first app to grow a second Gantt screen
|
|
8017
|
+
* immediately has two copies to keep in step (PPM had a project plan, a project schedule and a
|
|
8018
|
+
* portfolio roadmap). Shipping the item beside the chart means the labels ride the DS baseline
|
|
8019
|
+
* locales in all four languages and a consumer supplies only state and a callback.
|
|
8020
|
+
*
|
|
8021
|
+
* `defaultValue` is the CALLER's load-time default — `'week'` on a single project's plan, `'month'`
|
|
8022
|
+
* on a portfolio spanning years — because the trigger's accent "non-default" dot should light only
|
|
8023
|
+
* once the user has left that screen's own entry point.
|
|
8024
|
+
*
|
|
8025
|
+
* `labelKeyPrefix` exists for a consumer that already ships its own translated period labels and
|
|
8026
|
+
* does not want the DS baseline (PPM's `ppm.projects.plan.zoom.*` predate this helper). It appends
|
|
8027
|
+
* `.label` for the trigger and `.<zoom>` per option, matching the baseline layout exactly.
|
|
7661
8028
|
*/
|
|
7662
|
-
declare
|
|
7663
|
-
|
|
7664
|
-
|
|
7665
|
-
|
|
7666
|
-
/**
|
|
7667
|
-
|
|
7668
|
-
|
|
7669
|
-
|
|
7670
|
-
|
|
7671
|
-
|
|
7672
|
-
|
|
7673
|
-
|
|
7674
|
-
|
|
7675
|
-
|
|
7676
|
-
|
|
7677
|
-
|
|
7678
|
-
|
|
7679
|
-
|
|
7680
|
-
|
|
7681
|
-
|
|
7682
|
-
|
|
7683
|
-
|
|
7684
|
-
|
|
7685
|
-
|
|
7686
|
-
|
|
7687
|
-
|
|
7688
|
-
|
|
7689
|
-
|
|
7690
|
-
|
|
7691
|
-
|
|
7692
|
-
|
|
7693
|
-
|
|
7694
|
-
|
|
7695
|
-
|
|
8029
|
+
declare function ganttPeriodBarItem(spec: {
|
|
8030
|
+
value: GanttZoom;
|
|
8031
|
+
defaultValue: GanttZoom;
|
|
8032
|
+
disabled?: boolean;
|
|
8033
|
+
/** Key namespace for the trigger + option captions. Defaults to the DS baseline `gantt.period`. */
|
|
8034
|
+
labelKeyPrefix?: string;
|
|
8035
|
+
onSelect: (zoom: GanttZoom) => void;
|
|
8036
|
+
}): MagicBarAction;
|
|
8037
|
+
/**
|
|
8038
|
+
* The **Indent** / **Outdent** pair as magic-bar actions, for a chart whose consumer maps outline
|
|
8039
|
+
* level onto something it can persist.
|
|
8040
|
+
*
|
|
8041
|
+
* Two actions rather than one toggle: they are opposite verbs with independent availability (a row
|
|
8042
|
+
* can be indentable and not outdentable, and at the top of a list neither applies), and a toggle
|
|
8043
|
+
* would have to pick a label for a state the user cannot see.
|
|
8044
|
+
*
|
|
8045
|
+
* ## Icon-only, and why they are still discoverable
|
|
8046
|
+
* Both are icon-only despite `skills/shell-magic-bar-views.md` §5's default, because the
|
|
8047
|
+
* indent/outdent glyph pair is one of the few marks a user genuinely reads without help — it is the
|
|
8048
|
+
* same pair every word processor, IDE and desktop planner has shipped for thirty years, and the two
|
|
8049
|
+
* are identified by being MIRRORS of each other, which a label cannot improve on. They also sort
|
|
8050
|
+
* inside Add/Delete/Edit under {@link orderMagicBarItems}, so they never take the outer edge from a
|
|
8051
|
+
* verb that needs it.
|
|
8052
|
+
*
|
|
8053
|
+
* ## Omitted, never dimmed
|
|
8054
|
+
* An unavailable verb is left OUT of the returned array — the magic bar renders no disabled
|
|
8055
|
+
* buttons at all (`skills/shell-magic-bar-views.md` §6). The bar is one small shared strip
|
|
8056
|
+
* and its cost is measured in how many things it shows at once, so a dimmed button spends that
|
|
8057
|
+
* budget on an action the user cannot take. This pair is the clearest case: at most ONE of the two
|
|
8058
|
+
* is ever available for a given row, so dimming doubled the group's width to say nothing. What
|
|
8059
|
+
* availability depends on is also on screen while the bar is being read — a row already nested
|
|
8060
|
+
* cannot nest further — so the dimmed state was not teaching anything the chart did not show.
|
|
8061
|
+
*
|
|
8062
|
+
* Returns 0, 1 or 2 actions. Spread it; never index it.
|
|
8063
|
+
*/
|
|
8064
|
+
declare function ganttOutlineBarItems(spec: {
|
|
8065
|
+
canIndent: boolean;
|
|
8066
|
+
canOutdent: boolean;
|
|
8067
|
+
onIndent: () => void;
|
|
8068
|
+
onOutdent: () => void;
|
|
8069
|
+
}): MagicBarAction[];
|
|
7696
8070
|
|
|
7697
8071
|
/**
|
|
7698
|
-
*
|
|
8072
|
+
* Normalise a label / query for comparison: case-folded and stripped of combining marks, so a
|
|
8073
|
+
* search for `resume` finds `Résumé` and an Arabic query matches regardless of harakat.
|
|
7699
8074
|
*
|
|
7700
|
-
*
|
|
7701
|
-
* (`
|
|
7702
|
-
*
|
|
7703
|
-
|
|
7704
|
-
|
|
7705
|
-
|
|
8075
|
+
* `NFD` + strip `\p{M}` rather than a hand-rolled accent table: the table approach covers Latin-1
|
|
8076
|
+
* and silently fails on every other script this platform ships (`ar`, `ur`), which is precisely the
|
|
8077
|
+
* locale pair where a user is most likely to type an unmarked form.
|
|
8078
|
+
*/
|
|
8079
|
+
declare function normalizeGanttSearchText(value: string): string;
|
|
8080
|
+
/**
|
|
8081
|
+
* Filter a Gantt row set to the rows a query is "about", **preserving tree context**.
|
|
7706
8082
|
*
|
|
7707
|
-
*
|
|
7708
|
-
*
|
|
7709
|
-
* `{appId}` is just a *priority hint* that bumps that lookup to the top of
|
|
7710
|
-
* the entity picker when the app is live. See {@link LookupRegistration.scope}
|
|
7711
|
-
* for the rationale.
|
|
8083
|
+
* A flat `rows.filter(matches)` is the obvious implementation and it is wrong here for two
|
|
8084
|
+
* independent reasons, both of which change what the user sees rather than merely how it looks:
|
|
7712
8085
|
*
|
|
7713
|
-
*
|
|
7714
|
-
* `
|
|
7715
|
-
*
|
|
8086
|
+
* 1. **A matching child whose parent is filtered out becomes a root.** `flattenRows` treats an
|
|
8087
|
+
* unknown `parentId` as a root, so a task matching "deploy" would jump to depth 0 and lose the
|
|
8088
|
+
* milestone that gives it meaning. The user asked to find a row, not to re-parent it.
|
|
8089
|
+
* 2. **A matching parent whose children are filtered out stops being a group.** Its chevron
|
|
8090
|
+
* disappears and its derived span collapses to its own dates — so searching for a milestone
|
|
8091
|
+
* silently changes the bar the chart draws for it.
|
|
8092
|
+
*
|
|
8093
|
+
* So the kept set is the **closure** of the matches over both directions of the tree: every match,
|
|
8094
|
+
* every ancestor of a match (context above), and every descendant of a match (context below).
|
|
8095
|
+
* Searching a milestone's name shows that milestone with its whole task list intact; searching a
|
|
8096
|
+
* task's name shows the task under its own milestone.
|
|
8097
|
+
*
|
|
8098
|
+
* Order is preserved — this is a filter, never a re-sort. An empty / whitespace query returns the
|
|
8099
|
+
* input array by reference, so a non-searching chart pays nothing and its `computed` never
|
|
8100
|
+
* invalidates on identity alone.
|
|
7716
8101
|
*/
|
|
7717
|
-
declare
|
|
7718
|
-
|
|
7719
|
-
|
|
7720
|
-
|
|
7721
|
-
|
|
7722
|
-
|
|
7723
|
-
|
|
7724
|
-
|
|
7725
|
-
|
|
7726
|
-
|
|
7727
|
-
|
|
7728
|
-
|
|
7729
|
-
|
|
7730
|
-
|
|
7731
|
-
|
|
7732
|
-
|
|
7733
|
-
|
|
7734
|
-
|
|
7735
|
-
|
|
7736
|
-
|
|
7737
|
-
|
|
7738
|
-
|
|
7739
|
-
|
|
7740
|
-
|
|
7741
|
-
|
|
7742
|
-
|
|
7743
|
-
|
|
7744
|
-
|
|
7745
|
-
|
|
7746
|
-
|
|
7747
|
-
|
|
7748
|
-
|
|
7749
|
-
|
|
7750
|
-
|
|
7751
|
-
|
|
7752
|
-
|
|
7753
|
-
|
|
7754
|
-
|
|
7755
|
-
|
|
7756
|
-
|
|
7757
|
-
|
|
7758
|
-
|
|
7759
|
-
|
|
7760
|
-
|
|
7761
|
-
|
|
7762
|
-
|
|
7763
|
-
|
|
7764
|
-
|
|
7765
|
-
|
|
7766
|
-
|
|
7767
|
-
|
|
7768
|
-
|
|
7769
|
-
|
|
7770
|
-
|
|
7771
|
-
|
|
7772
|
-
|
|
7773
|
-
*
|
|
7774
|
-
|
|
7775
|
-
|
|
7776
|
-
|
|
7777
|
-
|
|
7778
|
-
|
|
7779
|
-
|
|
7780
|
-
|
|
7781
|
-
|
|
7782
|
-
|
|
7783
|
-
|
|
7784
|
-
|
|
7785
|
-
|
|
7786
|
-
|
|
7787
|
-
|
|
7788
|
-
|
|
7789
|
-
|
|
7790
|
-
|
|
7791
|
-
|
|
7792
|
-
|
|
7793
|
-
|
|
7794
|
-
|
|
8102
|
+
declare function filterGanttRows(rows: readonly GanttRow[], query: string): readonly GanttRow[];
|
|
8103
|
+
|
|
8104
|
+
/**
|
|
8105
|
+
* Apply a {@link GanttRowReorder} to a plain `GanttRow[]`, returning a new array.
|
|
8106
|
+
*
|
|
8107
|
+
* Optional: a consumer that persists to a server and re-reads does not need it. It exists for the
|
|
8108
|
+
* two cases that do — an optimistic update while the write is in flight, and an app whose row
|
|
8109
|
+
* order is client-side only — because the fiddly part is not the parent change, it is keeping the
|
|
8110
|
+
* moved row's DESCENDANTS with it and landing the block after the previous sibling's whole
|
|
8111
|
+
* subtree rather than immediately after that sibling's own row.
|
|
8112
|
+
*
|
|
8113
|
+
* The moved row's `parentId` is rewritten to the move's parent; every other row is untouched, so a
|
|
8114
|
+
* consumer's extra fields survive.
|
|
8115
|
+
*/
|
|
8116
|
+
declare function applyGanttRowReorder(rows: readonly GanttRow[], move: GanttRowReorder): GanttRow[];
|
|
8117
|
+
|
|
8118
|
+
/** The 14 rendered field kinds. Drives the control the renderer picks. */
|
|
8119
|
+
type FlyFormQuestionType = 'Text' | 'MultilineText' | 'Number' | 'Email' | 'Date' | 'DateTime' | 'Boolean' | 'SingleSelect' | 'MultipleSelect' | 'RadioButton' | 'Country' | 'File' | 'MultiFile' | 'Image';
|
|
8120
|
+
/**
|
|
8121
|
+
* A selectable option on a choice field (SingleSelect / MultipleSelect /
|
|
8122
|
+
* RadioButton). `linkedQuestionIds` drive conditional branching: selecting this
|
|
8123
|
+
* option reveals those (branch-target) fields. `score` is author-only and is only
|
|
8124
|
+
* surfaced to the viewer when the host opts in via `[showScore]` (a scorecard);
|
|
8125
|
+
* a respondent-facing form leaves `showScore` false and never renders it.
|
|
8126
|
+
*/
|
|
8127
|
+
interface FlyFormOption {
|
|
8128
|
+
id: string;
|
|
8129
|
+
label: string;
|
|
8130
|
+
score?: number;
|
|
8131
|
+
linkedQuestionIds?: string[];
|
|
8132
|
+
}
|
|
8133
|
+
/** Per-type constraints/affordances an author can attach to a field. */
|
|
8134
|
+
interface FlyFormFieldOptions {
|
|
8135
|
+
minLength?: number;
|
|
8136
|
+
maxLength?: number;
|
|
8137
|
+
numericMin?: number;
|
|
8138
|
+
numericMax?: number;
|
|
8139
|
+
rows?: number;
|
|
8140
|
+
maxFileSizeMb?: number;
|
|
8141
|
+
maxFileCount?: number;
|
|
8142
|
+
allowedExtensions?: string[];
|
|
8143
|
+
hasSearch?: boolean;
|
|
8144
|
+
}
|
|
8145
|
+
/**
|
|
8146
|
+
* A single form field. `isBranchTarget` fields start hidden. `sectionId` /
|
|
8147
|
+
* `criteriaGroup` are additive grouping hints a scorecard uses; they are ignored
|
|
8148
|
+
* by the respondent-facing survey path, so binding them changes nothing there.
|
|
8149
|
+
*/
|
|
8150
|
+
interface FlyFormQuestion {
|
|
8151
|
+
id: string;
|
|
8152
|
+
text: string;
|
|
8153
|
+
description?: string;
|
|
8154
|
+
type: FlyFormQuestionType;
|
|
8155
|
+
required: boolean;
|
|
8156
|
+
isBranchTarget: boolean;
|
|
8157
|
+
/** Additive: an author-hidden field. `false` excludes it from the visible set (and thus from
|
|
8158
|
+
* required-enforcement); omitted / `true` renders as normal. Mirrors the backend `IsVisible`. */
|
|
8159
|
+
isVisible?: boolean;
|
|
8160
|
+
fieldOptions?: FlyFormFieldOptions;
|
|
8161
|
+
options: FlyFormOption[];
|
|
8162
|
+
/** Additive: groups fields into a visual section (scorecard). Ignored by surveys. */
|
|
8163
|
+
sectionId?: string;
|
|
8164
|
+
/** Additive: labels the weighted-criteria group a scored field belongs to. Ignored by surveys. */
|
|
8165
|
+
criteriaGroup?: string;
|
|
8166
|
+
}
|
|
8167
|
+
/** A full form definition — the top-level `[definition]` binding. */
|
|
8168
|
+
interface FlyFormDefinition {
|
|
8169
|
+
title: string;
|
|
8170
|
+
description?: string;
|
|
8171
|
+
declaration?: string;
|
|
8172
|
+
questions: FlyFormQuestion[];
|
|
8173
|
+
}
|
|
8174
|
+
/** How an opted-in `[showScore]` host renders a choice option's points. */
|
|
8175
|
+
type FlyFormScoreDisplay = 'inline' | 'badge';
|
|
8176
|
+
/**
|
|
8177
|
+
* The polymorphic answer payload for one field. Only the field(s) relevant to the
|
|
8178
|
+
* type are populated:
|
|
8179
|
+
* - text: Text / MultilineText / Email
|
|
8180
|
+
* - number: Number
|
|
8181
|
+
* - dateValue: Date / DateTime (raw `<input>` value string)
|
|
8182
|
+
* - boolValue: Boolean
|
|
8183
|
+
* - selectedOptionIds: SingleSelect / MultipleSelect / RadioButton / Country
|
|
8184
|
+
* - fileIds: File / MultiFile / Image (filled by the host after upload; this
|
|
8185
|
+
* component emits it empty and surfaces the raw selection via `fileSelected`)
|
|
8186
|
+
*/
|
|
8187
|
+
interface FlyFormAnswerValue {
|
|
8188
|
+
text?: string;
|
|
8189
|
+
number?: number;
|
|
8190
|
+
dateValue?: string;
|
|
8191
|
+
boolValue?: boolean;
|
|
8192
|
+
selectedOptionIds?: string[];
|
|
8193
|
+
fileIds?: string[];
|
|
8194
|
+
}
|
|
8195
|
+
/** One field's answer — the unit emitted by `answersChange` / `submit`. */
|
|
8196
|
+
interface FlyFormAnswer {
|
|
8197
|
+
questionId: string;
|
|
8198
|
+
value: FlyFormAnswerValue;
|
|
8199
|
+
}
|
|
8200
|
+
/**
|
|
8201
|
+
* Raw file selection surfaced by File / MultiFile / Image fields. The host wires
|
|
8202
|
+
* this to its own upload API and, once ids are known, feeds them back via the
|
|
8203
|
+
* `[answers]` prefill (`fileIds`). The DS component never touches an upload endpoint.
|
|
8204
|
+
*/
|
|
8205
|
+
interface FlyFileSelection {
|
|
8206
|
+
questionId: string;
|
|
8207
|
+
files: File[];
|
|
7795
8208
|
}
|
|
7796
8209
|
|
|
8210
|
+
/** A render segment: either an ungrouped field (`group === null`) or a titled `criteriaGroup` section.
|
|
8211
|
+
* `index` is the field's running position across the whole form (drives unique element ids). */
|
|
8212
|
+
interface FlyFormFieldGroup {
|
|
8213
|
+
group: string | null;
|
|
8214
|
+
items: {
|
|
8215
|
+
q: FlyFormQuestion;
|
|
8216
|
+
index: number;
|
|
8217
|
+
}[];
|
|
8218
|
+
}
|
|
7797
8219
|
/**
|
|
7798
|
-
*
|
|
7799
|
-
* items, keyed by `kind` and `appId`.
|
|
8220
|
+
* **`fly-dynamic-form`** — the design-system data-contract-driven form renderer.
|
|
7800
8221
|
*
|
|
7801
|
-
*
|
|
7802
|
-
*
|
|
7803
|
-
*
|
|
8222
|
+
* Renders a {@link FlyFormDefinition} (14 field types) into an accessible,
|
|
8223
|
+
* theme-aware form, owning all the fiddly behaviour a form needs: conditional
|
|
8224
|
+
* **branching** (options reveal branch-target fields), per-visible-field
|
|
8225
|
+
* **required validation**, a **declaration** acceptance gate, and a **readonly**
|
|
8226
|
+
* replay mode. It is a platform surface — zero coupling to any specific app, and
|
|
8227
|
+
* (deliberately) no coupling to an upload API: File / Image / MultiFile fields
|
|
8228
|
+
* surface the raw selection via {@link fileSelected} and emit `fileIds` empty; the
|
|
8229
|
+
* host wires the upload and feeds ids back through the `[answers]` prefill.
|
|
7804
8230
|
*
|
|
7805
|
-
*
|
|
7806
|
-
*
|
|
8231
|
+
* The historical **`fly-survey-form`** selector is retained on this same component
|
|
8232
|
+
* (multi-selector), so every existing `<fly-survey-form>` binding keeps working
|
|
8233
|
+
* unchanged. Surveys never sets {@link showScore}, so its behaviour (never rendering
|
|
8234
|
+
* `option.score`) is identical. A scorecard host opts into score display with
|
|
8235
|
+
* `[showScore]="true"`.
|
|
7807
8236
|
*
|
|
7808
|
-
*
|
|
7809
|
-
*
|
|
8237
|
+
* i18n is self-sufficient through the `form.*` keys in `DS_BASELINE_LOCALES`
|
|
8238
|
+
* (en/ar/fr/ur), overridable by any consumer key of the same name. RTL works via
|
|
8239
|
+
* logical CSS. Styling uses DS theme tokens (`--surface-*`, `--label-*`,
|
|
8240
|
+
* `--separator`, `--fill-*`, `--accent`, `--system-*`) with light-neutral
|
|
8241
|
+
* fallbacks so it stays readable even in a consumer that hasn't mapped them.
|
|
8242
|
+
*
|
|
8243
|
+
* @example
|
|
8244
|
+
* ```html
|
|
8245
|
+
* <fly-dynamic-form
|
|
8246
|
+
* [definition]="def"
|
|
8247
|
+
* [answers]="prefill"
|
|
8248
|
+
* [showScore]="true"
|
|
8249
|
+
* (answersChange)="draft = $event"
|
|
8250
|
+
* (validityChange)="valid = $event"
|
|
8251
|
+
* (fileSelected)="upload($event)"
|
|
8252
|
+
* (submit)="persist($event)" />
|
|
8253
|
+
* ```
|
|
7810
8254
|
*/
|
|
7811
|
-
declare class
|
|
7812
|
-
private readonly
|
|
7813
|
-
/**
|
|
7814
|
-
|
|
8255
|
+
declare class FlyDynamicFormComponent implements OnInit {
|
|
8256
|
+
private readonly _i18n;
|
|
8257
|
+
/** The form to render. */
|
|
8258
|
+
readonly definition: _angular_core.InputSignal<FlyFormDefinition>;
|
|
8259
|
+
/** Replay mode — every control is disabled and no validation errors / submit show.
|
|
8260
|
+
* Aliased to `[readonly]` (the public binding); the class member avoids shadowing
|
|
8261
|
+
* the TypeScript `readonly` keyword. */
|
|
8262
|
+
readonly isReadonly: _angular_core.InputSignal<boolean>;
|
|
8263
|
+
/** Hides the submit button while leaving every control interactive — the author's
|
|
8264
|
+
* pre-publish PREVIEW, which must let you open dropdowns and try the form out but has
|
|
8265
|
+
* nothing to submit to. Distinct from `readonly`, which disables the controls outright
|
|
8266
|
+
* (a submission replay). A host that hides submit should not bind `(submit)`. */
|
|
8267
|
+
readonly hideSubmit: _angular_core.InputSignal<boolean>;
|
|
8268
|
+
/** Prefill answers (e.g. a saved draft or a completed response). Answers for
|
|
8269
|
+
* currently-hidden branch targets are ignored. */
|
|
8270
|
+
readonly answers: _angular_core.InputSignal<readonly FlyFormAnswer[]>;
|
|
8271
|
+
/** Additive, opt-in: render each choice option's `score` (a weighted scorecard).
|
|
8272
|
+
* Defaults false so the respondent-facing survey path never leaks the answer key. */
|
|
8273
|
+
readonly showScore: _angular_core.InputSignal<boolean>;
|
|
8274
|
+
/** How an opted-in score is rendered next to an option (`badge` chip or `inline` text). */
|
|
8275
|
+
readonly scoreDisplay: _angular_core.InputSignal<FlyFormScoreDisplay>;
|
|
8276
|
+
/** The full visible answer set on every change. */
|
|
8277
|
+
readonly answersChange: _angular_core.OutputEmitterRef<FlyFormAnswer[]>;
|
|
8278
|
+
/** Required-field validity on every change (does NOT include the declaration gate). */
|
|
8279
|
+
readonly validityChange: _angular_core.OutputEmitterRef<boolean>;
|
|
8280
|
+
/** Fires only when the form is valid AND (if a declaration is set) accepted. */
|
|
8281
|
+
readonly submit: _angular_core.OutputEmitterRef<FlyFormAnswer[]>;
|
|
8282
|
+
/** Raw file selection for a File / MultiFile / Image field — the host uploads
|
|
8283
|
+
* and feeds the resulting ids back via `[answers]`. */
|
|
8284
|
+
readonly fileSelected: _angular_core.OutputEmitterRef<FlyFileSelection>;
|
|
8285
|
+
private readonly _base;
|
|
8286
|
+
/** questionId → answer value. Only ever contains VISIBLE, non-empty answers. */
|
|
8287
|
+
private readonly _values;
|
|
8288
|
+
/** questionId → locally-picked File[] (transient, pre-upload). Never emitted as ids. */
|
|
8289
|
+
private readonly _fileSelections;
|
|
8290
|
+
private readonly _declarationAccepted;
|
|
8291
|
+
private readonly _submitAttempted;
|
|
8292
|
+
/** questionIds the user has interacted with — gates when a required error shows. */
|
|
8293
|
+
private readonly _interacted;
|
|
8294
|
+
/** Per-field local file-validation error message (already localized). */
|
|
8295
|
+
private readonly _fileErrors;
|
|
8296
|
+
private readonly _countryOptions;
|
|
8297
|
+
constructor();
|
|
8298
|
+
ngOnInit(): void;
|
|
8299
|
+
/** The set of field ids currently shown (base fields + revealed branch targets). */
|
|
8300
|
+
readonly visibleQuestionIds: _angular_core.Signal<Set<string>>;
|
|
8301
|
+
/** Definition fields filtered to the visible set, in definition order. */
|
|
8302
|
+
readonly visibleQuestions: _angular_core.Signal<FlyFormQuestion[]>;
|
|
7815
8303
|
/**
|
|
7816
|
-
*
|
|
7817
|
-
*
|
|
7818
|
-
* `
|
|
7819
|
-
*
|
|
7820
|
-
* Returns `null` when no renderer is registered; the host falls back to a generic
|
|
7821
|
-
* `plainTextFallback` chip.
|
|
8304
|
+
* The visible fields laid out in render order, segmented by `criteriaGroup`: fields that share a
|
|
8305
|
+
* (non-empty) group render together inside one titled section (a scorecard's weighted-criteria
|
|
8306
|
+
* grouping); a field with no `criteriaGroup` is its own ungrouped segment and renders flat, exactly
|
|
8307
|
+
* as before. Each item keeps its running index across the whole form so element ids stay unique.
|
|
7822
8308
|
*/
|
|
7823
|
-
|
|
8309
|
+
readonly groupedQuestions: _angular_core.Signal<FlyFormFieldGroup[]>;
|
|
8310
|
+
readonly declarationRequired: _angular_core.Signal<boolean>;
|
|
8311
|
+
/** Required-field validity (declaration NOT included — see {@link canSubmit}). */
|
|
8312
|
+
readonly isValid: _angular_core.Signal<boolean>;
|
|
8313
|
+
/** Whether `(submit)` may fire: valid required set AND declaration accepted (if any). */
|
|
8314
|
+
readonly canSubmit: _angular_core.Signal<boolean>;
|
|
8315
|
+
readonly declarationAccepted: _angular_core.Signal<boolean>;
|
|
8316
|
+
fieldId(index: number): string;
|
|
8317
|
+
descId(index: number): string;
|
|
8318
|
+
errId(index: number): string;
|
|
8319
|
+
describedBy(q: FlyFormQuestion, index: number): string | null;
|
|
8320
|
+
isChoice(type: FlyFormQuestionType): boolean;
|
|
8321
|
+
isFile(type: FlyFormQuestionType): boolean;
|
|
8322
|
+
/** Types rendered as a native input group inside `<fieldset><legend>`. */
|
|
8323
|
+
isFieldset(type: FlyFormQuestionType): boolean;
|
|
8324
|
+
isCountry(type: FlyFormQuestionType): boolean;
|
|
7824
8325
|
/**
|
|
7825
|
-
*
|
|
7826
|
-
* replaces the prior entry; the disposal handle for the prior registration becomes
|
|
7827
|
-
* a no-op.
|
|
8326
|
+
* Types rendered with the DS `<fly-select>` (labelled via `ariaLabel`).
|
|
7828
8327
|
*
|
|
7829
|
-
*
|
|
7830
|
-
*
|
|
8328
|
+
* Every select-like type now qualifies. `hasSearch` used to gate the CONTROL, which left a plain
|
|
8329
|
+
* SingleSelect on a native `<select>` — an OS-chrome popup that cannot be themed (it paints its
|
|
8330
|
+
* rows with the control's translucent background over a white backing, so the list rendered
|
|
8331
|
+
* white-on-white on the dark shell). `hasSearch` now only decides whether the DS panel carries a
|
|
8332
|
+
* search box; see {@link selectSearchable}.
|
|
7831
8333
|
*/
|
|
7832
|
-
|
|
8334
|
+
usesDsSelect(q: FlyFormQuestion): boolean;
|
|
8335
|
+
/** Search box: always for Country (the list is ~200 long), else only when the author asked. */
|
|
8336
|
+
selectSearchable(q: FlyFormQuestion): boolean;
|
|
7833
8337
|
/**
|
|
7834
|
-
*
|
|
7835
|
-
*
|
|
7836
|
-
*
|
|
8338
|
+
* The points to show for a choice option, or null to render nothing. Non-null only when the host
|
|
8339
|
+
* opted in via `[showScore]` and the option actually carries a score — this is the sole gate that
|
|
8340
|
+
* keeps a respondent-facing survey (which never binds `showScore`) from leaking the answer key.
|
|
7837
8341
|
*/
|
|
7838
|
-
|
|
8342
|
+
optionScore(opt: FlyFormOption): number | null;
|
|
8343
|
+
/** Whether a required error should be visible for a field right now. */
|
|
8344
|
+
showError(q: FlyFormQuestion): boolean;
|
|
8345
|
+
fileError(q: FlyFormQuestion): string | null;
|
|
8346
|
+
textValue(q: FlyFormQuestion): string;
|
|
8347
|
+
numberValue(q: FlyFormQuestion): number | null;
|
|
8348
|
+
dateValue(q: FlyFormQuestion): string;
|
|
8349
|
+
boolValue(q: FlyFormQuestion): boolean | null;
|
|
8350
|
+
singleValue(q: FlyFormQuestion): string | null;
|
|
8351
|
+
isSelected(q: FlyFormQuestion, optionId: string): boolean;
|
|
8352
|
+
countryOptions(q: FlyFormQuestion): readonly FlySelectOption[];
|
|
8353
|
+
selectOptions(q: FlyFormQuestion): readonly FlySelectOption[];
|
|
8354
|
+
fileNames(q: FlyFormQuestion): string[];
|
|
8355
|
+
acceptFor(q: FlyFormQuestion): string;
|
|
8356
|
+
onText(q: FlyFormQuestion, value: string): void;
|
|
8357
|
+
onNumber(q: FlyFormQuestion, value: string): void;
|
|
8358
|
+
onDate(q: FlyFormQuestion, value: string): void;
|
|
8359
|
+
onBoolean(q: FlyFormQuestion, value: boolean): void;
|
|
8360
|
+
onSingleSelect(q: FlyFormQuestion, value: string | readonly string[] | null): void;
|
|
8361
|
+
onRadio(q: FlyFormQuestion, optionId: string): void;
|
|
8362
|
+
onMultiToggle(q: FlyFormQuestion, optionId: string, checked: boolean): void;
|
|
8363
|
+
onFiles(q: FlyFormQuestion, input: HTMLInputElement): void;
|
|
8364
|
+
onDeclarationToggle(checked: boolean): void;
|
|
8365
|
+
onSubmit(): void;
|
|
8366
|
+
private _touch;
|
|
8367
|
+
private _setFileError;
|
|
8368
|
+
private _mutate;
|
|
8369
|
+
private _emit;
|
|
8370
|
+
private _collectAnswers;
|
|
8371
|
+
private _isAnswered;
|
|
8372
|
+
private _isEmptyValue;
|
|
8373
|
+
private _selectedIds;
|
|
7839
8374
|
/**
|
|
7840
|
-
*
|
|
7841
|
-
*
|
|
7842
|
-
*
|
|
8375
|
+
* The set of visible field ids for a given answer map. Base (non-branch-target)
|
|
8376
|
+
* fields are always visible; a branch target becomes visible when a
|
|
8377
|
+
* currently-visible field has a selected option that links to it. Computed to a
|
|
8378
|
+
* fixpoint so chained reveals work, and cycle-safe: the visible set only grows and
|
|
8379
|
+
* iteration is capped at `questions.length` passes, so an A↔B link cycle terminates.
|
|
8380
|
+
*
|
|
8381
|
+
* This is the TypeScript twin of the backend Fly.Sdk.Forms `BranchResolver`
|
|
8382
|
+
* fixpoint — the two must stay in lockstep so server + client agree on which fields
|
|
8383
|
+
* are active.
|
|
7843
8384
|
*/
|
|
7844
|
-
|
|
7845
|
-
/**
|
|
7846
|
-
private
|
|
7847
|
-
|
|
7848
|
-
|
|
7849
|
-
static ɵfac: _angular_core.ɵɵFactoryDeclaration<AgentDropRegistry, never>;
|
|
7850
|
-
static ɵprov: _angular_core.ɵɵInjectableDeclaration<AgentDropRegistry>;
|
|
8385
|
+
private _computeVisibleIds;
|
|
8386
|
+
/** Imperative localization for file-validation messages (the pipe covers view strings). */
|
|
8387
|
+
private _t;
|
|
8388
|
+
static ɵfac: _angular_core.ɵɵFactoryDeclaration<FlyDynamicFormComponent, never>;
|
|
8389
|
+
static ɵcmp: _angular_core.ɵɵComponentDeclaration<FlyDynamicFormComponent, "fly-dynamic-form, fly-survey-form", never, { "definition": { "alias": "definition"; "required": true; "isSignal": true; }; "isReadonly": { "alias": "readonly"; "required": false; "isSignal": true; }; "hideSubmit": { "alias": "hideSubmit"; "required": false; "isSignal": true; }; "answers": { "alias": "answers"; "required": false; "isSignal": true; }; "showScore": { "alias": "showScore"; "required": false; "isSignal": true; }; "scoreDisplay": { "alias": "scoreDisplay"; "required": false; "isSignal": true; }; }, { "answersChange": "answersChange"; "validityChange": "validityChange"; "submit": "submit"; "fileSelected": "fileSelected"; }, never, never, true, never>;
|
|
7851
8390
|
}
|
|
7852
8391
|
|
|
7853
|
-
|
|
7854
|
-
|
|
7855
|
-
|
|
7856
|
-
|
|
7857
|
-
|
|
7858
|
-
|
|
7859
|
-
|
|
7860
|
-
|
|
7861
|
-
|
|
7862
|
-
*/
|
|
7863
|
-
type
|
|
7864
|
-
/**
|
|
7865
|
-
|
|
7866
|
-
|
|
7867
|
-
*
|
|
7868
|
-
*
|
|
7869
|
-
*
|
|
7870
|
-
*
|
|
7871
|
-
*
|
|
7872
|
-
*/
|
|
7873
|
-
|
|
7874
|
-
|
|
7875
|
-
|
|
7876
|
-
|
|
7877
|
-
|
|
7878
|
-
|
|
7879
|
-
|
|
7880
|
-
|
|
7881
|
-
|
|
7882
|
-
|
|
7883
|
-
|
|
7884
|
-
|
|
7885
|
-
|
|
7886
|
-
|
|
7887
|
-
|
|
7888
|
-
|
|
7889
|
-
readonly originRect?: DOMRect;
|
|
7890
|
-
/** Optional HTML snippet rendered inside the flight ghost. Callers are
|
|
7891
|
-
* responsible for escaping untrusted text — the bus does not sanitise.
|
|
7892
|
-
* Defaults (when omitted) to a strong-wrapped escape of the payload's
|
|
7893
|
-
* `plainTextFallback` rendered by the panel host. */
|
|
7894
|
-
readonly originPreviewHtml?: string;
|
|
8392
|
+
interface FlyCountry {
|
|
8393
|
+
/** ISO 3166-1 alpha-2 code (uppercase), e.g. `AE`. */
|
|
8394
|
+
code: string;
|
|
8395
|
+
/** English display name. */
|
|
8396
|
+
name: string;
|
|
8397
|
+
}
|
|
8398
|
+
/** Frozen alpha-2 list, alphabetical by English name. */
|
|
8399
|
+
declare const FLY_COUNTRIES: readonly FlyCountry[];
|
|
8400
|
+
|
|
8401
|
+
/** Backend `CommentReportReason` enum — string-persisted, member names frozen. */
|
|
8402
|
+
type FlyCommentReportReason = 'Spam' | 'Harassment' | 'OffTopic' | 'Misinformation' | 'Inappropriate' | 'Other';
|
|
8403
|
+
/** Backend `CommentReportStatus` enum — string-persisted, member names frozen. */
|
|
8404
|
+
type FlyCommentReportStatus = 'Open' | 'UnderReview' | 'ActionTaken' | 'Dismissed';
|
|
8405
|
+
/**
|
|
8406
|
+
* One comment, at any depth. `isDeleted` comments render as a tombstone (the
|
|
8407
|
+
* host still supplies `body`-less structural fields so the reply subtree stays
|
|
8408
|
+
* navigable; the component never assumes `body` is present when `isDeleted`).
|
|
8409
|
+
* `canEdit` / `canDelete` / `canModerate` are pre-resolved by the host (Cerbos
|
|
8410
|
+
* decision or equivalent) — the component never evaluates authorization itself.
|
|
8411
|
+
*/
|
|
8412
|
+
interface FlyComment {
|
|
8413
|
+
id: string;
|
|
8414
|
+
authorUserId: string;
|
|
8415
|
+
authorDisplayName?: string;
|
|
8416
|
+
authorAvatarUrl?: string;
|
|
8417
|
+
parentCommentId?: string;
|
|
8418
|
+
depth: number;
|
|
8419
|
+
body: string;
|
|
8420
|
+
replyCount: number;
|
|
8421
|
+
isEdited: boolean;
|
|
8422
|
+
isDeleted: boolean;
|
|
8423
|
+
createdAt: string;
|
|
8424
|
+
updatedAt?: string;
|
|
8425
|
+
canEdit: boolean;
|
|
8426
|
+
canDelete: boolean;
|
|
8427
|
+
canModerate: boolean;
|
|
7895
8428
|
}
|
|
7896
8429
|
/**
|
|
7897
|
-
*
|
|
7898
|
-
*
|
|
7899
|
-
*
|
|
7900
|
-
*
|
|
8430
|
+
* A paged slice of comments at one nesting level — mirrors the service's
|
|
8431
|
+
* `GET .../comments?parentCommentId=&page=&pageSize=` shape. Every depth is
|
|
8432
|
+
* paged independently: the root page and each expanded parent's reply page are
|
|
8433
|
+
* separate {@link FlyCommentPage} instances tracked by the host.
|
|
7901
8434
|
*/
|
|
7902
|
-
|
|
7903
|
-
|
|
7904
|
-
|
|
8435
|
+
interface FlyCommentPage {
|
|
8436
|
+
items: FlyComment[];
|
|
8437
|
+
page: number;
|
|
8438
|
+
pageSize: number;
|
|
8439
|
+
total: number;
|
|
8440
|
+
hasMore: boolean;
|
|
8441
|
+
}
|
|
8442
|
+
/** `loadReplies` request — expand a collapsed reply subtree, one page at a time. */
|
|
8443
|
+
interface FlyCommentLoadRepliesRequest {
|
|
8444
|
+
parentCommentId: string;
|
|
8445
|
+
page: number;
|
|
8446
|
+
}
|
|
8447
|
+
/** `loadMore` request — next page at the root level (`parentCommentId` omitted) or under a parent. */
|
|
8448
|
+
interface FlyCommentLoadMoreRequest {
|
|
8449
|
+
parentCommentId?: string;
|
|
8450
|
+
page: number;
|
|
8451
|
+
}
|
|
8452
|
+
/** `submit` request — a new root comment (`parentCommentId` omitted) or a reply. */
|
|
8453
|
+
interface FlyCommentSubmitRequest {
|
|
8454
|
+
body: string;
|
|
8455
|
+
parentCommentId?: string;
|
|
8456
|
+
}
|
|
8457
|
+
/** `edit` request — author-only body edit of an existing comment. */
|
|
8458
|
+
interface FlyCommentEditRequest {
|
|
8459
|
+
commentId: string;
|
|
8460
|
+
body: string;
|
|
8461
|
+
}
|
|
8462
|
+
/** `delete` request — soft delete (tombstone), author or moderator. */
|
|
8463
|
+
interface FlyCommentDeleteRequest {
|
|
8464
|
+
commentId: string;
|
|
8465
|
+
}
|
|
8466
|
+
/** `report` request — typed reason + optional free-text detail. */
|
|
8467
|
+
interface FlyCommentReportRequest {
|
|
8468
|
+
commentId: string;
|
|
8469
|
+
reason: FlyCommentReportReason;
|
|
8470
|
+
detail?: string;
|
|
8471
|
+
}
|
|
8472
|
+
/** `lockToggle` request — moderator lock/unlock of the whole thread. */
|
|
8473
|
+
interface FlyCommentLockToggleRequest {
|
|
8474
|
+
locked: boolean;
|
|
7905
8475
|
}
|
|
7906
8476
|
|
|
7907
8477
|
/**
|
|
7908
|
-
*
|
|
8478
|
+
* **`fly-comment-thread`** — the design-system generic threaded-comments renderer.
|
|
7909
8479
|
*
|
|
7910
|
-
*
|
|
7911
|
-
*
|
|
7912
|
-
*
|
|
7913
|
-
*
|
|
7914
|
-
*
|
|
7915
|
-
*
|
|
8480
|
+
* Renders a {@link FlyCommentPage} (root comments) plus lazily-fetched nested
|
|
8481
|
+
* reply pages into an accessible, theme-aware thread: reply composer, inline
|
|
8482
|
+
* edit, soft-delete (tombstone render), typed report-with-reason dialog, and
|
|
8483
|
+
* moderator affordances (lock/unlock, delete-any). It is a platform surface —
|
|
8484
|
+
* transport-agnostic like `fly-survey-form` / `fly-dynamic-form`: this component
|
|
8485
|
+
* never calls an API. It only renders the pages the host hands it via
|
|
8486
|
+
* `[rootPage]` / `[repliesByParent]` and emits typed requests
|
|
8487
|
+
* (`loadReplies`/`loadMore`/`submit`/`edit`/`delete`/`report`/`lockToggle`) —
|
|
8488
|
+
* the host owns HTTP, optimistic-insert reconciliation, and any live-update
|
|
8489
|
+
* channel (SignalR, polling, …).
|
|
7916
8490
|
*
|
|
7917
|
-
*
|
|
7918
|
-
*
|
|
7919
|
-
*
|
|
8491
|
+
* Nested replies are fetched **lazily on expand** (`loadReplies`, never an
|
|
8492
|
+
* eager load-all) — the explicit fix for the legacy unpaged-children scale bug
|
|
8493
|
+
* — and each level pages independently via `loadMore`.
|
|
7920
8494
|
*
|
|
7921
|
-
*
|
|
7922
|
-
*
|
|
7923
|
-
*
|
|
8495
|
+
* The `comments` core app owns no user profile data, so `FlyComment` carries
|
|
8496
|
+
* `authorUserId` and an OPTIONAL `authorDisplayName`. Rather than make every host
|
|
8497
|
+
* map names in itself (and render GUIDs when it forgets), bind
|
|
8498
|
+
* `[resolveDisplayName]` to `FlyUserDirectoryService.label` — see
|
|
8499
|
+
* {@link FlyCommentThreadComponent.resolveDisplayName}. Still transport-agnostic:
|
|
8500
|
+
* the resolver is a function the host hands over, not a call this component makes.
|
|
8501
|
+
*
|
|
8502
|
+
* i18n is self-sufficient through the `comment.*` keys in `DS_BASELINE_LOCALES`
|
|
8503
|
+
* (en/ar/fr/ur), overridable by any consumer key of the same name. RTL works via
|
|
8504
|
+
* logical CSS. Styling uses DS theme tokens (`--surface-*`, `--label-*`,
|
|
8505
|
+
* `--separator`, `--fill-*`, `--accent`, `--system-*`) with light-neutral
|
|
8506
|
+
* fallbacks so it stays readable even in a consumer that hasn't mapped them.
|
|
8507
|
+
*
|
|
8508
|
+
* @example
|
|
8509
|
+
* ```html
|
|
8510
|
+
* <fly-comment-thread
|
|
8511
|
+
* [rootPage]="rootPage()"
|
|
8512
|
+
* [repliesByParent]="repliesByParent()"
|
|
8513
|
+
* [currentUserId]="me.id"
|
|
8514
|
+
* [resolveDisplayName]="directory.label"
|
|
8515
|
+
* [canModerateThread]="canModerate()"
|
|
8516
|
+
* [isLocked]="thread().isLocked"
|
|
8517
|
+
* (loadReplies)="onLoadReplies($event)"
|
|
8518
|
+
* (loadMore)="onLoadMore($event)"
|
|
8519
|
+
* (submit)="onSubmit($event)"
|
|
8520
|
+
* (edit)="onEdit($event)"
|
|
8521
|
+
* (delete)="onDelete($event)"
|
|
8522
|
+
* (report)="onReport($event)"
|
|
8523
|
+
* (lockToggle)="onLockToggle($event)" />
|
|
8524
|
+
* ```
|
|
7924
8525
|
*/
|
|
7925
|
-
declare class
|
|
7926
|
-
|
|
7927
|
-
|
|
7928
|
-
* actions dispatched AFTER they subscribe — late subscribers see nothing
|
|
7929
|
-
* retroactively. Use {@link lastAction} for the latest snapshot. */
|
|
7930
|
-
readonly actions$: Observable<AgentAction>;
|
|
7931
|
-
/** Most recent action — for DevTools, smoke tests, and late-subscriber
|
|
7932
|
-
* catch-up. Null until the first successful dispatch. */
|
|
7933
|
-
readonly lastAction: _angular_core.WritableSignal<AgentAction<unknown> | null>;
|
|
8526
|
+
declare class FlyCommentThreadComponent {
|
|
8527
|
+
/** The root-level comment page (accumulated across `loadMore` calls by the host). */
|
|
8528
|
+
readonly rootPage: _angular_core.InputSignal<FlyCommentPage>;
|
|
7934
8529
|
/**
|
|
7935
|
-
*
|
|
7936
|
-
*
|
|
7937
|
-
*
|
|
7938
|
-
*
|
|
7939
|
-
* a busy state on the originating control — e.g. a card swapping its
|
|
7940
|
-
* sparkle icon for a spinner while the agent panel mints the optimistic
|
|
7941
|
-
* thread and starts the request. Identity check (`bus.inFlight() === act`)
|
|
7942
|
-
* is the panel-side contract; dispatchers usually project to a stable id
|
|
7943
|
-
* inside the payload (e.g. <c>reportId</c>) to scope busy-state visually.
|
|
7944
|
-
*
|
|
7945
|
-
* If multiple dispatches race, the latest wins — the prior in-flight
|
|
7946
|
-
* action is dropped on the floor here (the panel may still handle it,
|
|
7947
|
-
* but the dispatcher's busy indicator follows the newer action). Apps
|
|
7948
|
-
* that need stricter single-flight semantics should guard at the call
|
|
7949
|
-
* site (the agent-panel's <c>_pendingTempThreadId</c> already does so
|
|
7950
|
-
* for the explain verb).
|
|
8530
|
+
* Accumulated reply page per expanded parent (keyed by `parentCommentId`), also
|
|
8531
|
+
* accumulated across `loadMore` calls by the host. Additive to the frozen
|
|
8532
|
+
* contract's `rootPage` input — required because a lazily-nested tree has no
|
|
8533
|
+
* other channel to carry fetched reply data back into the component.
|
|
7951
8534
|
*/
|
|
7952
|
-
readonly
|
|
8535
|
+
readonly repliesByParent: _angular_core.InputSignal<Readonly<Record<string, FlyCommentPage>>>;
|
|
8536
|
+
/** Current sort order label (host owns re-fetch on {@link sortChange}; purely descriptive here otherwise). */
|
|
8537
|
+
readonly sort: _angular_core.InputSignal<"newest" | "oldest">;
|
|
8538
|
+
/** Locked threads disable the composer (root + reply) entirely, for every user. */
|
|
8539
|
+
readonly isLocked: _angular_core.InputSignal<boolean>;
|
|
8540
|
+
/** The signed-in user's id — gates the "report" affordance (can't report your own comment). */
|
|
8541
|
+
readonly currentUserId: _angular_core.InputSignal<string | null>;
|
|
8542
|
+
/** Replay / read-only mode — hides composer, reply, edit, delete, report, and lock affordances.
|
|
8543
|
+
* Aliased to `[readonly]` (the public binding); the class member avoids shadowing the
|
|
8544
|
+
* TypeScript `readonly` keyword. */
|
|
8545
|
+
readonly isReadonly: _angular_core.InputSignal<boolean>;
|
|
8546
|
+
/** Thread-scoped moderator permission (lock/unlock). Additive — distinct from the
|
|
8547
|
+
* per-comment `canModerate` flag, which gates delete-any on that specific comment. */
|
|
8548
|
+
readonly canModerateThread: _angular_core.InputSignal<boolean>;
|
|
7953
8549
|
/**
|
|
7954
|
-
*
|
|
8550
|
+
* Optional id→name lookup, for the common case where the backend DTO carries only
|
|
8551
|
+
* `authorUserId`. The `comments` core app owns no user profile data, so without
|
|
8552
|
+
* this every host had to map display names into `authorDisplayName` itself — and
|
|
8553
|
+
* a host that forgot rendered raw GUIDs at the reader.
|
|
7955
8554
|
*
|
|
7956
|
-
*
|
|
7957
|
-
*
|
|
7958
|
-
*
|
|
7959
|
-
*
|
|
7960
|
-
* version, invalid kind). The error message carries the field path
|
|
7961
|
-
* so the caller can fix the offending field.
|
|
8555
|
+
* Bind `FlyUserDirectoryService.label` (a signal-backed read-through cache that
|
|
8556
|
+
* resolves on demand and batches). Because the component reads it during render,
|
|
8557
|
+
* the name appears by itself once the lookup lands — the host keeps a plain
|
|
8558
|
+
* page signal, with no `computed` derivation and no priming.
|
|
7962
8559
|
*
|
|
7963
|
-
*
|
|
7964
|
-
*
|
|
7965
|
-
*
|
|
7966
|
-
|
|
7967
|
-
dispatch<T>(action: AgentAction<T>): void;
|
|
7968
|
-
/**
|
|
7969
|
-
* Subscriber contract: call after the handler for {@link inFlight}
|
|
7970
|
-
* completes (success or fail). Only clears {@link inFlight} if it still
|
|
7971
|
-
* points at the passed action — a no-op when a later dispatch already
|
|
7972
|
-
* superseded it. Pass the same action reference the subscriber received
|
|
7973
|
-
* from {@link actions$}; identity is the gate.
|
|
8560
|
+
* The component still never calls an API: this is a function the HOST supplies,
|
|
8561
|
+
* exactly like `fly-entity-lookup`'s `LOOKUP_APP_NAME_RESOLVER`. Absent (or
|
|
8562
|
+
* returning `null`), rendering falls back as before. See {@link authorLabel} for
|
|
8563
|
+
* the resolution order.
|
|
7974
8564
|
*/
|
|
7975
|
-
|
|
8565
|
+
readonly resolveDisplayName: _angular_core.InputSignal<((userId: string) => string | null) | null>;
|
|
8566
|
+
/** Expand a collapsed reply subtree — always page 1 of that parent. */
|
|
8567
|
+
readonly loadReplies: _angular_core.OutputEmitterRef<{
|
|
8568
|
+
parentCommentId: string;
|
|
8569
|
+
page: number;
|
|
8570
|
+
}>;
|
|
8571
|
+
/** Fetch the next page at a level: root when `parentCommentId` is omitted, else that parent's replies. */
|
|
8572
|
+
readonly loadMore: _angular_core.OutputEmitterRef<{
|
|
8573
|
+
parentCommentId?: string;
|
|
8574
|
+
page: number;
|
|
8575
|
+
}>;
|
|
8576
|
+
/** A new root comment (`parentCommentId` omitted) or reply. */
|
|
8577
|
+
readonly submit: _angular_core.OutputEmitterRef<{
|
|
8578
|
+
body: string;
|
|
8579
|
+
parentCommentId?: string;
|
|
8580
|
+
}>;
|
|
8581
|
+
/** Author-only body edit of an existing comment. */
|
|
8582
|
+
readonly edit: _angular_core.OutputEmitterRef<{
|
|
8583
|
+
commentId: string;
|
|
8584
|
+
body: string;
|
|
8585
|
+
}>;
|
|
8586
|
+
/** Soft delete (tombstone) — author's own comment, or any comment for a moderator. */
|
|
8587
|
+
readonly delete: _angular_core.OutputEmitterRef<{
|
|
8588
|
+
commentId: string;
|
|
8589
|
+
}>;
|
|
8590
|
+
/** Typed report submission. */
|
|
8591
|
+
readonly report: _angular_core.OutputEmitterRef<{
|
|
8592
|
+
commentId: string;
|
|
8593
|
+
reason: FlyCommentReportReason;
|
|
8594
|
+
detail?: string;
|
|
8595
|
+
}>;
|
|
8596
|
+
/** Moderator lock/unlock of the whole thread. */
|
|
8597
|
+
readonly lockToggle: _angular_core.OutputEmitterRef<{
|
|
8598
|
+
locked: boolean;
|
|
8599
|
+
}>;
|
|
8600
|
+
/** Additive: a sort-order pick from the header control — the host re-fetches page 1 in that order. */
|
|
8601
|
+
readonly sortChange: _angular_core.OutputEmitterRef<"newest" | "oldest">;
|
|
8602
|
+
private readonly _base;
|
|
8603
|
+
readonly reportReasons: readonly FlyCommentReportReason[];
|
|
8604
|
+
/** commentIds whose reply subtree is currently expanded/visible. */
|
|
8605
|
+
private readonly _expanded;
|
|
8606
|
+
/** Composer draft text, keyed by parentCommentId (root uses {@link ROOT_DRAFT_KEY}). */
|
|
8607
|
+
private readonly _drafts;
|
|
8608
|
+
/** commentIds whose reply composer box is currently open (distinct from `_expanded`, which toggles the read view). */
|
|
8609
|
+
private readonly _replyBoxOpen;
|
|
8610
|
+
private readonly _editingId;
|
|
8611
|
+
private readonly _editDraft;
|
|
8612
|
+
private readonly _confirmingDeleteId;
|
|
8613
|
+
private readonly _reportingId;
|
|
8614
|
+
private readonly _reportReason;
|
|
8615
|
+
private readonly _reportDetail;
|
|
8616
|
+
readonly rootDraft: _angular_core.Signal<string>;
|
|
8617
|
+
readonly editingId: _angular_core.Signal<string | null>;
|
|
8618
|
+
readonly confirmingDeleteId: _angular_core.Signal<string | null>;
|
|
8619
|
+
readonly reportingId: _angular_core.Signal<string | null>;
|
|
8620
|
+
readonly reportReason: _angular_core.Signal<FlyCommentReportReason | null>;
|
|
8621
|
+
readonly reportDetail: _angular_core.Signal<string>;
|
|
8622
|
+
fieldId(suffix: string): string;
|
|
8623
|
+
isExpanded(commentId: string): boolean;
|
|
8624
|
+
isReplyBoxOpen(commentId: string): boolean;
|
|
8625
|
+
repliesFor(commentId: string): FlyCommentPage | undefined;
|
|
8626
|
+
replyDraft(commentId: string): string;
|
|
8627
|
+
isOwn(comment: FlyComment): boolean;
|
|
7976
8628
|
/**
|
|
7977
|
-
*
|
|
7978
|
-
*
|
|
7979
|
-
*
|
|
7980
|
-
*
|
|
7981
|
-
* lets the UI distinguish "handler finished" from "user said no" in
|
|
7982
|
-
* telemetry / logs without sniffing a "reason" parameter.
|
|
8629
|
+
* The name to render for a comment's author. Resolution order:
|
|
8630
|
+
* explicit `authorDisplayName` (a host that already knows the name, or a
|
|
8631
|
+
* backend that returns one, always wins) → {@link resolveDisplayName} →
|
|
8632
|
+
* the raw `authorUserId`.
|
|
7983
8633
|
*
|
|
7984
|
-
*
|
|
7985
|
-
*
|
|
8634
|
+
* The raw id remains the last resort rather than a placeholder: it is stable,
|
|
8635
|
+
* unique, and lets a reader correlate two comments by the same author even
|
|
8636
|
+
* when the directory is unreachable.
|
|
7986
8637
|
*/
|
|
7987
|
-
|
|
7988
|
-
|
|
7989
|
-
|
|
8638
|
+
authorLabel(comment: FlyComment): string;
|
|
8639
|
+
/** First character of {@link authorLabel}, for the avatar-initials fallback. */
|
|
8640
|
+
authorInitial(comment: FlyComment): string;
|
|
8641
|
+
canReport(comment: FlyComment): boolean;
|
|
8642
|
+
canReply(): boolean;
|
|
8643
|
+
canDeleteComment(comment: FlyComment): boolean;
|
|
8644
|
+
canEditComment(comment: FlyComment): boolean;
|
|
8645
|
+
formatDate(iso: string): string;
|
|
8646
|
+
onRootDraftChange(value: string): void;
|
|
8647
|
+
submitRoot(): void;
|
|
8648
|
+
toggleReplies(comment: FlyComment): void;
|
|
8649
|
+
private _expand;
|
|
8650
|
+
loadMoreRoot(): void;
|
|
8651
|
+
loadMoreReplies(parentId: string): void;
|
|
8652
|
+
openReplyBox(commentId: string): void;
|
|
8653
|
+
closeReplyBox(commentId: string): void;
|
|
8654
|
+
onReplyDraftChange(commentId: string, value: string): void;
|
|
8655
|
+
submitReply(commentId: string): void;
|
|
8656
|
+
startEdit(comment: FlyComment): void;
|
|
8657
|
+
onEditDraftChange(value: string): void;
|
|
8658
|
+
saveEdit(comment: FlyComment): void;
|
|
8659
|
+
cancelEdit(): void;
|
|
8660
|
+
requestDelete(comment: FlyComment): void;
|
|
8661
|
+
confirmDelete(comment: FlyComment): void;
|
|
8662
|
+
cancelDelete(): void;
|
|
8663
|
+
openReport(comment: FlyComment): void;
|
|
8664
|
+
onReportReasonChange(reason: FlyCommentReportReason): void;
|
|
8665
|
+
onReportDetailChange(value: string): void;
|
|
8666
|
+
submitReport(): void;
|
|
8667
|
+
closeReport(): void;
|
|
8668
|
+
/** Space would otherwise scroll the page while the backdrop (role="button") is focused. */
|
|
8669
|
+
onOverlayBackdropSpace(event: Event): void;
|
|
8670
|
+
toggleLock(): void;
|
|
8671
|
+
onSortPick(next: 'newest' | 'oldest'): void;
|
|
8672
|
+
private _setDraft;
|
|
8673
|
+
static ɵfac: _angular_core.ɵɵFactoryDeclaration<FlyCommentThreadComponent, never>;
|
|
8674
|
+
static ɵcmp: _angular_core.ɵɵComponentDeclaration<FlyCommentThreadComponent, "fly-comment-thread", never, { "rootPage": { "alias": "rootPage"; "required": true; "isSignal": true; }; "repliesByParent": { "alias": "repliesByParent"; "required": false; "isSignal": true; }; "sort": { "alias": "sort"; "required": false; "isSignal": true; }; "isLocked": { "alias": "isLocked"; "required": false; "isSignal": true; }; "currentUserId": { "alias": "currentUserId"; "required": false; "isSignal": true; }; "isReadonly": { "alias": "readonly"; "required": false; "isSignal": true; }; "canModerateThread": { "alias": "canModerateThread"; "required": false; "isSignal": true; }; "resolveDisplayName": { "alias": "resolveDisplayName"; "required": false; "isSignal": true; }; }, { "loadReplies": "loadReplies"; "loadMore": "loadMore"; "submit": "submit"; "edit": "edit"; "delete": "delete"; "report": "report"; "lockToggle": "lockToggle"; "sortChange": "sortChange"; }, never, never, true, never>;
|
|
7990
8675
|
}
|
|
7991
8676
|
|
|
7992
8677
|
/**
|
|
7993
|
-
*
|
|
7994
|
-
*
|
|
7995
|
-
*
|
|
7996
|
-
* no CSS transitions racing layout. Honours `prefers-reduced-motion`: the
|
|
7997
|
-
* ghost is appended then removed without animating when the user asked for
|
|
7998
|
-
* less motion (so DOM side-effects stay consistent).
|
|
7999
|
-
*
|
|
8000
|
-
* Lifecycle:
|
|
8001
|
-
* 1. The agent panel calls {@link registerTarget} in `ngAfterViewInit`
|
|
8002
|
-
* with its header element.
|
|
8003
|
-
* 2. A source app dispatches an `AgentAction` carrying an `originRect`
|
|
8004
|
-
* from `getBoundingClientRect()` on the click target.
|
|
8005
|
-
* 3. The bus subscriber calls {@link flyInto} with that rect.
|
|
8006
|
-
* 4. The animator creates a fixed-position ghost at the origin, animates
|
|
8007
|
-
* transform + opacity toward the registered target's rect, then
|
|
8008
|
-
* removes itself on `onfinish` / `oncancel`.
|
|
8009
|
-
*
|
|
8010
|
-
* Uses `getBoundingClientRect()` (physical viewport coords) so the animation
|
|
8011
|
-
* is RTL-correct without inset-inline math — the rect already encodes the
|
|
8012
|
-
* physical position regardless of `dir`.
|
|
8013
|
-
*
|
|
8014
|
-
* The 900 ms duration and easing curve are deliberately hardcoded — making
|
|
8015
|
-
* them configurable surfaces an API the host can't usefully tune without
|
|
8016
|
-
* understanding motion design as a whole.
|
|
8678
|
+
* A proof-of-work challenge issued by `Fly.Sdk.Captcha` (`CaptchaChallenge`).
|
|
8679
|
+
* The solver must find `n` in `[0, maxNumber)` such that
|
|
8680
|
+
* `sha256HexLower(salt + n) === challenge`.
|
|
8017
8681
|
*/
|
|
8018
|
-
|
|
8019
|
-
/**
|
|
8020
|
-
|
|
8021
|
-
|
|
8022
|
-
|
|
8023
|
-
|
|
8024
|
-
|
|
8025
|
-
|
|
8026
|
-
|
|
8027
|
-
|
|
8028
|
-
|
|
8029
|
-
|
|
8030
|
-
|
|
8031
|
-
* Animate a ghost element from {@link from} to the registered target's
|
|
8032
|
-
* rect. No-ops when:
|
|
8033
|
-
* - no target is registered (silent — panel may not be mounted yet)
|
|
8034
|
-
* - running outside a browser (SSR safety)
|
|
8035
|
-
* - the user has `prefers-reduced-motion: reduce` set (DOM is still
|
|
8036
|
-
* touched so callers see consistent side-effects, but no animation
|
|
8037
|
-
* runs)
|
|
8038
|
-
*
|
|
8039
|
-
* The ghost is appended to `document.body` (not the panel) so a parent
|
|
8040
|
-
* `overflow: hidden` on the panel can't clip the flight path.
|
|
8041
|
-
*/
|
|
8042
|
-
flyInto(from: DOMRect, opts?: {
|
|
8043
|
-
previewHtml?: string;
|
|
8044
|
-
}): void;
|
|
8045
|
-
static ɵfac: _angular_core.ɵɵFactoryDeclaration<AgentFlightAnimator, never>;
|
|
8046
|
-
static ɵprov: _angular_core.ɵɵInjectableDeclaration<AgentFlightAnimator>;
|
|
8682
|
+
interface FlyCaptchaChallenge {
|
|
8683
|
+
/** Always `"SHA-256"` today. */
|
|
8684
|
+
algorithm: string;
|
|
8685
|
+
/** Lowercase-hex SHA-256 of `salt + number` for the secret solution number. */
|
|
8686
|
+
challenge: string;
|
|
8687
|
+
/** Base64 random salt, unique per challenge. */
|
|
8688
|
+
salt: string;
|
|
8689
|
+
/** HMAC signature binding challenge + maxNumber + expiresAt (server-verified). */
|
|
8690
|
+
signature: string;
|
|
8691
|
+
/** Exclusive upper bound of the search space (difficulty). */
|
|
8692
|
+
maxNumber: number;
|
|
8693
|
+
/** ISO-8601 instant after which the solution is rejected. Echoed back verbatim. */
|
|
8694
|
+
expiresAt: string;
|
|
8047
8695
|
}
|
|
8048
|
-
|
|
8049
8696
|
/**
|
|
8050
|
-
*
|
|
8051
|
-
*
|
|
8052
|
-
*
|
|
8053
|
-
*
|
|
8054
|
-
*
|
|
8055
|
-
* looking at**, and the design's reference implementation re-publishes the whole
|
|
8056
|
-
* set on every selection, tab and save (`pubTabActions`). Two consequences shape
|
|
8057
|
-
* every type below:
|
|
8058
|
-
*
|
|
8059
|
-
* 1. **A contribution is a full replace, never a patch.** There is no "add one
|
|
8060
|
-
* action" call, because the publisher never knows what the previous view left
|
|
8061
|
-
* behind. That also collapses D5's `search: null` ("suppress") vs `search`
|
|
8062
|
-
* absent distinction — under full replace both simply mean "this view offers
|
|
8063
|
-
* no search".
|
|
8064
|
-
* 2. **Render data and behaviour are separated in the type system.** Each family
|
|
8065
|
-
* has a `*Spec` base carrying ONLY the fields that affect what is painted;
|
|
8066
|
-
* the publisher-facing type extends it with callbacks, and the shell-facing
|
|
8067
|
-
* `*View` type extends it with bound invokers. The base IS the equality
|
|
8068
|
-
* surface {@link MagicBarRegistry} dedupes on — a re-publish whose specs are
|
|
8069
|
-
* unchanged must not disturb the shell, even though its closures are brand
|
|
8070
|
-
* new objects every time (an arrow function in a component method never
|
|
8071
|
-
* compares equal to its predecessor). See `magic-bar-projection.ts`.
|
|
8072
|
-
*
|
|
8073
|
-
* **Strings are i18n keys, never resolved text** — same rule as
|
|
8074
|
-
* {@link AgentCommandRegistration} (`labelKey` / `descriptionKey` / `hintKey`),
|
|
8075
|
-
* for the same two reasons: a contribution outlives a locale switch (a resolved
|
|
8076
|
-
* label would silently go stale until the publisher happened to re-publish), and
|
|
8077
|
-
* keys are locale-invariant so the dedupe fingerprint doesn't churn when the user
|
|
8078
|
-
* changes language. Keys resolve in the OWNING app's bundle.
|
|
8079
|
-
*
|
|
8080
|
-
* **Every `*Key` has an optional `*Params` sibling** ({@link MagicBarTextParams}),
|
|
8081
|
-
* fed straight to `I18nService.t(key, params)`. Without it a count-carrying string
|
|
8082
|
-
* ("Search 1,204 tasks…") forces the publisher to pass pre-formatted TEXT as the
|
|
8083
|
-
* key: it renders correctly in `en`, renders identically untranslated in ar/fr/ur,
|
|
8084
|
-
* and no locale tool can see it. Params participate in the dedupe fingerprint, so
|
|
8085
|
-
* a changing count re-paints.
|
|
8086
|
-
*
|
|
8087
|
-
* Which of D5 §4's "dynamics the shell must honor" live where:
|
|
8088
|
-
*
|
|
8089
|
-
* | # | Dynamic | Owner |
|
|
8090
|
-
* |---|---|---|
|
|
8091
|
-
* | 1 | Live re-publication, idempotent replace | {@link MagicBarRegistry} (here) |
|
|
8092
|
-
* | 2 | Disabled ≠ hidden, auto disabled-tooltip | contract keeps `disabled` rows; `fly-magic-actions` renders + suffixes |
|
|
8093
|
-
* | 3 | `toolbarPopIn` 40 ms stagger | renderer — it tracks on {@link MagicBarActionSpec.id}, which is why ids are unique across the WHOLE contribution |
|
|
8094
|
-
* | 4 | i18n on every label/tip | contract (keys + params, above) |
|
|
8095
|
-
* | 5 | Fixed right cluster is not contributable | contract — no slot exists for it |
|
|
8096
|
-
* | 6 | Mobile renders the same contribution | contract carries no form-factor branch; `openWidth` is a desktop hint mobile ignores |
|
|
8097
|
-
* | 7 | `shortcut` reserved (design has no shortcut affordance yet) | contract — carried, unrendered |
|
|
8098
|
-
*
|
|
8099
|
-
* On dynamic 3 specifically: the registry's dedupe does NOT stop the stagger
|
|
8100
|
-
* replaying, and believing it does would produce a renderer that re-animates on
|
|
8101
|
-
* every click. Dedupe fires only when *nothing painted* changed, and the dominant
|
|
8102
|
-
* case — `disabled: !hasSelection` — changes the fingerprint on every selection.
|
|
8103
|
-
* What holds the DOM still is the renderer's `@for (…; track item.id)`.
|
|
8697
|
+
* The solved payload, matching `Fly.Sdk.Captcha.CaptchaSolution` field-for-field
|
|
8698
|
+
* (camelCase Web JSON). Serialized to the opaque base64 token the backend decodes:
|
|
8699
|
+
* `base64(utf8(JSON.stringify(solution)))` — i.e. `Convert.ToBase64String` +
|
|
8700
|
+
* `JsonSerializerDefaults.Web`. Every field except `number` is echoed from the
|
|
8701
|
+
* challenge unchanged so the server's stateless signature check passes.
|
|
8104
8702
|
*/
|
|
8105
|
-
|
|
8106
|
-
|
|
8703
|
+
interface FlyCaptchaSolution {
|
|
8704
|
+
algorithm: string;
|
|
8705
|
+
challenge: string;
|
|
8706
|
+
salt: string;
|
|
8707
|
+
number: number;
|
|
8708
|
+
signature: string;
|
|
8709
|
+
maxNumber: number;
|
|
8710
|
+
expiresAt: string;
|
|
8711
|
+
}
|
|
8712
|
+
/** The solver lifecycle surfaced by the component's `state()` signal. */
|
|
8713
|
+
type FlyCaptchaState = 'idle' | 'verifying' | 'verified' | 'expired' | 'error';
|
|
8714
|
+
|
|
8715
|
+
/** Lowercase-hex SHA-256 of `input` via Web Crypto — matches `Convert.ToHexStringLower(SHA256…)`. */
|
|
8716
|
+
declare function flyCaptchaSha256Hex(input: string): Promise<string>;
|
|
8717
|
+
/** Standard base64 of the UTF-8 bytes of `s` — matches .NET `Convert.ToBase64String`. */
|
|
8718
|
+
declare function flyCaptchaBase64Utf8(s: string): string;
|
|
8107
8719
|
/**
|
|
8108
|
-
*
|
|
8109
|
-
*
|
|
8110
|
-
*
|
|
8111
|
-
*
|
|
8112
|
-
* A union rather than the boolean `danger` this started as: the design already
|
|
8113
|
-
* demands a second colour, and widening a shipped `danger?: boolean` into a union
|
|
8114
|
-
* later would mean REMOVING an interface member — MAJOR under `tools/ds-compat`
|
|
8115
|
-
* (rule 7), which forks the federation singleton for every remote.
|
|
8720
|
+
* Builds the opaque base64 token the backend's `CaptchaSolution.FromToken` expects.
|
|
8721
|
+
* Exported so a host (or a test) can construct/verify the token shape without the
|
|
8722
|
+
* component.
|
|
8116
8723
|
*/
|
|
8117
|
-
|
|
8724
|
+
declare function flyCaptchaBuildToken(solution: FlyCaptchaSolution): string;
|
|
8118
8725
|
/**
|
|
8119
|
-
*
|
|
8120
|
-
* `
|
|
8726
|
+
* **`fly-captcha`** — the design-system client for the self-hosted proof-of-work
|
|
8727
|
+
* captcha (`Fly.Sdk.Captcha`).
|
|
8121
8728
|
*
|
|
8122
|
-
*
|
|
8123
|
-
*
|
|
8124
|
-
*
|
|
8125
|
-
|
|
8126
|
-
|
|
8127
|
-
|
|
8128
|
-
*
|
|
8129
|
-
*
|
|
8729
|
+
* Given a {@link FlyCaptchaChallenge}, it brute-forces `n` in `[0, maxNumber)`
|
|
8730
|
+
* until `sha256HexLower(salt + n) === challenge`, then emits the solution as the
|
|
8731
|
+
* base64 token the backend decodes ({@link flyCaptchaBuildToken}). The search
|
|
8732
|
+
* hashes candidates with a vendored **synchronous** SHA-256 ({@link sha256HexSync}
|
|
8733
|
+
* from `./sha256` — no `crypto.subtle`/promise overhead per candidate, which used
|
|
8734
|
+
* to dominate solve time), in chunks scheduled on `requestAnimationFrame` so a
|
|
8735
|
+
* chunk boundary still yields back to the browser between slices. It auto-starts
|
|
8736
|
+
* whenever the `[challenge]` input changes. Implements
|
|
8737
|
+
* {@link ControlValueAccessor} so it drops into a reactive form / `[(ngModel)]` —
|
|
8738
|
+
* the control value IS the token string.
|
|
8130
8739
|
*
|
|
8131
|
-
*
|
|
8132
|
-
*
|
|
8133
|
-
*
|
|
8134
|
-
* federated remote that predates per-window plumbing can still contribute —
|
|
8135
|
-
* {@link MagicBarRegistry} resolves an `appId`-keyed slot as a fallback.
|
|
8740
|
+
* Expiry is the host's concern to refresh: the component checks `expiresAt` up
|
|
8741
|
+
* front and while solving, emits {@link expired}, and stops. i18n is
|
|
8742
|
+
* self-sufficient via the `captcha.*` baseline keys; RTL works via logical CSS.
|
|
8136
8743
|
*
|
|
8137
|
-
*
|
|
8138
|
-
*
|
|
8139
|
-
*
|
|
8140
|
-
*
|
|
8744
|
+
* @example
|
|
8745
|
+
* ```html
|
|
8746
|
+
* <fly-captcha [challenge]="challenge()" (solved)="post($event)" (expired)="refresh()" />
|
|
8747
|
+
* ```
|
|
8141
8748
|
*/
|
|
8142
|
-
|
|
8143
|
-
|
|
8144
|
-
readonly
|
|
8749
|
+
declare class FlyCaptchaComponent implements ControlValueAccessor, OnDestroy {
|
|
8750
|
+
/** The challenge to solve. Setting (or replacing) it auto-starts a fresh solve. */
|
|
8751
|
+
readonly challenge: _angular_core.InputSignal<FlyCaptchaChallenge | null>;
|
|
8752
|
+
/** Candidates hashed synchronously in one slice before yielding back to the browser
|
|
8753
|
+
* on the next animation frame. Higher = fewer `requestAnimationFrame` hops (each
|
|
8754
|
+
* carries ~16ms of frame-boundary overhead), more synchronous work per slice.
|
|
8755
|
+
* 20,000 keeps a slice's own hashing time well under a long-task budget on modern
|
|
8756
|
+
* hardware (the vendored sync SHA-256 does several hundred thousand hashes/sec)
|
|
8757
|
+
* while needing only a handful of hops to clear the library's default difficulty. */
|
|
8758
|
+
readonly chunkSize: _angular_core.InputSignal<number>;
|
|
8759
|
+
/** The solution token once solved — the exact string to POST back to the backend. */
|
|
8760
|
+
readonly solved: _angular_core.OutputEmitterRef<string>;
|
|
8761
|
+
/** The challenge expired (up-front or mid-solve). The host should request a new one. */
|
|
8762
|
+
readonly expired: _angular_core.OutputEmitterRef<void>;
|
|
8763
|
+
readonly state: _angular_core.WritableSignal<FlyCaptchaState>;
|
|
8764
|
+
readonly token: _angular_core.WritableSignal<string | null>;
|
|
8765
|
+
/** Monotonic generation — bumped on every restart/destroy so a stale async chunk
|
|
8766
|
+
* or timer that captured an older generation no-ops instead of racing. */
|
|
8767
|
+
private _gen;
|
|
8768
|
+
private _raf;
|
|
8769
|
+
private _expiryTimer;
|
|
8770
|
+
private _onChange;
|
|
8771
|
+
private _onTouched;
|
|
8772
|
+
constructor();
|
|
8773
|
+
ngOnDestroy(): void;
|
|
8774
|
+
private _restart;
|
|
8775
|
+
/**
|
|
8776
|
+
* Hashes `[start, end)` synchronously with {@link sha256HexSync} — no per-candidate
|
|
8777
|
+
* `await`, so there is no promise/microtask overhead between candidates — then
|
|
8778
|
+
* yields to the next animation frame for the remainder. Bails to `error` state if
|
|
8779
|
+
* hashing itself throws (defensive; a pure function over a short string should not)
|
|
8780
|
+
* or if the whole `[0, maxNumber)` space is exhausted with no match, which means the
|
|
8781
|
+
* challenge is corrupt or was tampered with.
|
|
8782
|
+
*/
|
|
8783
|
+
private _solveChunk;
|
|
8784
|
+
private _onSolved;
|
|
8785
|
+
private _cancel;
|
|
8786
|
+
private _schedule;
|
|
8787
|
+
private _cancelSchedule;
|
|
8788
|
+
writeValue(value: string | null): void;
|
|
8789
|
+
registerOnChange(fn: (v: string | null) => void): void;
|
|
8790
|
+
registerOnTouched(fn: () => void): void;
|
|
8791
|
+
static ɵfac: _angular_core.ɵɵFactoryDeclaration<FlyCaptchaComponent, never>;
|
|
8792
|
+
static ɵcmp: _angular_core.ɵɵComponentDeclaration<FlyCaptchaComponent, "fly-captcha", never, { "challenge": { "alias": "challenge"; "required": false; "isSignal": true; }; "chunkSize": { "alias": "chunkSize"; "required": false; "isSignal": true; }; }, { "solved": "solved"; "expired": "expired"; }, never, never, true, never>;
|
|
8145
8793
|
}
|
|
8794
|
+
|
|
8146
8795
|
/**
|
|
8147
|
-
*
|
|
8148
|
-
* on the janitor path (`clear` after a window closes) without holding the
|
|
8149
|
-
* publisher.
|
|
8796
|
+
* Singleton registry of slash commands offered by the agent input palette.
|
|
8150
8797
|
*
|
|
8151
|
-
*
|
|
8152
|
-
*
|
|
8153
|
-
*
|
|
8154
|
-
*
|
|
8155
|
-
*
|
|
8156
|
-
*
|
|
8157
|
-
*
|
|
8798
|
+
* Lives in the DS so it crosses the federation boundary as a single instance via
|
|
8799
|
+
* `sharedMappings: ['@flyos/design-system']`. Federated remotes register
|
|
8800
|
+
* their commands at boot (and dispose on window close) without forking the shell.
|
|
8801
|
+
*
|
|
8802
|
+
* Storage is a signal store. `register` is O(1) for the unique-id case and O(n) when
|
|
8803
|
+
* replacing an existing id (filter then push). The append-then-replace strategy is
|
|
8804
|
+
* deliberate: registrations are rare (each one corresponds to a remote's app-init
|
|
8805
|
+
* effect), and the tradeoff buys us a stable id-collision contract — the *latest*
|
|
8806
|
+
* registration wins, and the previous handle's `dispose()` becomes a no-op rather
|
|
8807
|
+
* than removing the new entry.
|
|
8158
8808
|
*/
|
|
8159
|
-
declare
|
|
8160
|
-
|
|
8161
|
-
|
|
8162
|
-
readonly
|
|
8809
|
+
declare class AgentCommandRegistry {
|
|
8810
|
+
private readonly _commands;
|
|
8811
|
+
/** All currently-registered commands, in insertion order. */
|
|
8812
|
+
readonly all: Signal<readonly AgentCommandRegistration[]>;
|
|
8163
8813
|
/**
|
|
8164
|
-
*
|
|
8165
|
-
*
|
|
8166
|
-
*
|
|
8167
|
-
*
|
|
8814
|
+
* Returns a signal of commands whose scope is `'global'` OR whose `scope.appId` is in
|
|
8815
|
+
* the live app set. The signal recomputes when either the registry or `liveAppIds`
|
|
8816
|
+
* changes — pass a `Signal<ReadonlySet<string>>` from the host's app-registry service
|
|
8817
|
+
* for reactive filtering.
|
|
8168
8818
|
*/
|
|
8169
|
-
|
|
8170
|
-
/** Params for {@link labelKey} — the count-badged option ("All statuses ({{count}})"). */
|
|
8171
|
-
readonly labelParams?: MagicBarTextParams;
|
|
8819
|
+
visible(liveAppIds: ReadonlySet<string> | Signal<ReadonlySet<string>>): Signal<readonly AgentCommandRegistration[]>;
|
|
8172
8820
|
/**
|
|
8173
|
-
*
|
|
8174
|
-
*
|
|
8175
|
-
*
|
|
8176
|
-
|
|
8177
|
-
|
|
8178
|
-
|
|
8179
|
-
*
|
|
8180
|
-
*
|
|
8181
|
-
*
|
|
8182
|
-
* Thoughts' `top-trending` chose the second and kept its campaign/area filters in-page — that
|
|
8183
|
-
* is the gap this closes.
|
|
8184
|
-
*
|
|
8185
|
-
* ## What it does NOT license
|
|
8186
|
-
* Do not use it for captions. If the string is something your app authored — "All statuses",
|
|
8187
|
-
* "Newest first", an action name — it belongs in a locale bundle and `labelKey` is the field.
|
|
8188
|
-
* The test is where the string comes from: shipped with the app ⇒ `labelKey`; read from the
|
|
8189
|
-
* tenant's data ⇒ `label`. A resolved caption here is untranslatable text smuggled past the
|
|
8190
|
-
* locale tooling, which is precisely what the key-only rule exists to prevent.
|
|
8821
|
+
* Register a single command. Returns a handle whose `dispose()` removes the row by
|
|
8822
|
+
* id. If the same id is later re-registered, the original handle's `dispose()`
|
|
8823
|
+
* becomes a no-op (the newer registration owns the row). Idempotent disposal.
|
|
8824
|
+
*/
|
|
8825
|
+
register(cmd: AgentCommandRegistration): AgentCommandHandle;
|
|
8826
|
+
/**
|
|
8827
|
+
* Bulk register. Rolls back on duplicate id within the input batch (throws before any
|
|
8828
|
+
* row lands). Cross-batch duplicates against existing rows follow the standard
|
|
8829
|
+
* "latest wins" rule and do NOT trigger rollback.
|
|
8191
8830
|
*
|
|
8192
|
-
*
|
|
8831
|
+
* Returns a handle whose `dispose()` tears down every row registered by this call.
|
|
8193
8832
|
*/
|
|
8194
|
-
readonly
|
|
8195
|
-
|
|
8196
|
-
|
|
8197
|
-
|
|
8198
|
-
|
|
8199
|
-
|
|
8200
|
-
|
|
8201
|
-
|
|
8202
|
-
|
|
8203
|
-
/** Current selection — check glyph + 600 weight on the matching row. */
|
|
8204
|
-
readonly value: string;
|
|
8205
|
-
/** The unfiltered/unsorted baseline; the trigger shows its accent dot iff `value !== defaultValue`. */
|
|
8206
|
-
readonly defaultValue: string;
|
|
8207
|
-
}
|
|
8208
|
-
/** What a publisher supplies for a radio menu. */
|
|
8209
|
-
interface MagicBarRadioMenu extends MagicBarRadioMenuSpec {
|
|
8210
|
-
readonly onSelect?: (value: string) => void;
|
|
8211
|
-
}
|
|
8212
|
-
/** What the shell renders. `select` always exists; it no-ops when the publisher supplied no handler. */
|
|
8213
|
-
interface MagicBarRadioMenuView extends MagicBarRadioMenuSpec {
|
|
8214
|
-
select(value: string): void;
|
|
8833
|
+
registerAll(cmds: readonly AgentCommandRegistration[]): AgentCommandHandle;
|
|
8834
|
+
/** Tear down by id. Idempotent. */
|
|
8835
|
+
unregister(id: string): void;
|
|
8836
|
+
/** Monotonic counter; identifies which registration call currently owns each id. */
|
|
8837
|
+
private _generation;
|
|
8838
|
+
/** id → generation. Used so a stale handle's `dispose()` is a no-op after replacement. */
|
|
8839
|
+
private readonly _owners;
|
|
8840
|
+
static ɵfac: _angular_core.ɵɵFactoryDeclaration<AgentCommandRegistry, never>;
|
|
8841
|
+
static ɵprov: _angular_core.ɵɵInjectableDeclaration<AgentCommandRegistry>;
|
|
8215
8842
|
}
|
|
8843
|
+
|
|
8216
8844
|
/**
|
|
8217
|
-
*
|
|
8845
|
+
* Singleton registry of entity lookups offered by the `/lookup` typeahead.
|
|
8218
8846
|
*
|
|
8219
|
-
*
|
|
8220
|
-
*
|
|
8221
|
-
*
|
|
8847
|
+
* Mirrors {@link AgentCommandRegistry}'s federation-singleton story
|
|
8848
|
+
* (`sharedMappings: ['@flyos/design-system']`), id-collision
|
|
8849
|
+
* "latest wins" contract, and disposable-handle ergonomics. OS-core entities
|
|
8850
|
+
* (note / calendar event / file) register once at shell bootstrap via
|
|
8851
|
+
* `CORE_APP_LOOKUPS`; federated remotes (Circles: scenario / trend / signal)
|
|
8852
|
+
* register at remote-component boot and dispose on window close.
|
|
8853
|
+
*
|
|
8854
|
+
* **Scope semantics diverge from commands.** Commands HIDE when their `appId`
|
|
8855
|
+
* isn't in `liveAppIds`. Lookups DO NOT — they're always offered, and
|
|
8856
|
+
* `{appId}` is just a *priority hint* that bumps that lookup to the top of
|
|
8857
|
+
* the entity picker when the app is live. See {@link LookupRegistration.scope}
|
|
8858
|
+
* for the rationale.
|
|
8859
|
+
*
|
|
8860
|
+
* Storage is a signal store keyed on {@link LookupRegistration.entity}. Because
|
|
8861
|
+
* `entity` is the collision key, an app re-registering the same entity replaces
|
|
8862
|
+
* the prior descriptor; a stale handle's `dispose()` then no-ops.
|
|
8222
8863
|
*/
|
|
8223
|
-
|
|
8224
|
-
readonly
|
|
8225
|
-
/**
|
|
8226
|
-
readonly
|
|
8227
|
-
/** Params for {@link labelKey}, e.g. `{ count: 3 }` for "Delete {{count}} items". */
|
|
8228
|
-
readonly labelParams?: MagicBarTextParams;
|
|
8864
|
+
declare class AgentLookupRegistry {
|
|
8865
|
+
private readonly _lookups;
|
|
8866
|
+
/** All currently-registered lookups, in insertion order. */
|
|
8867
|
+
readonly all: Signal<readonly LookupRegistration[]>;
|
|
8229
8868
|
/**
|
|
8230
|
-
*
|
|
8231
|
-
* the design's icon transport. Reference {@link FLY_MAGIC_BAR_ICONS} by name
|
|
8232
|
-
* rather than hand-authoring; a publisher MAY author its own, subject to the
|
|
8233
|
-
* contract below.
|
|
8869
|
+
* All registered lookups, sorted by affinity to `liveAppIds`:
|
|
8234
8870
|
*
|
|
8235
|
-
*
|
|
8236
|
-
*
|
|
8237
|
-
*
|
|
8238
|
-
*
|
|
8239
|
-
* Anything else (a container element, an `on*` handler, `style`, `href`,
|
|
8240
|
-
* `fill="url(…)"`, a stray text node) rejects the WHOLE fragment: the button
|
|
8241
|
-
* renders with no glyph and logs. See `magic-actions-icon.ts`.
|
|
8871
|
+
* 1. Lookups whose `scope.appId` is in the live app set (in registration
|
|
8872
|
+
* order within that bucket).
|
|
8873
|
+
* 2. Then everything else — `'global'` lookups AND scoped lookups whose
|
|
8874
|
+
* app isn't currently live — in registration order.
|
|
8242
8875
|
*
|
|
8243
|
-
*
|
|
8244
|
-
*
|
|
8245
|
-
*
|
|
8246
|
-
*
|
|
8247
|
-
|
|
8248
|
-
readonly iconPath?: string;
|
|
8249
|
-
/** Default `'icon'`. */
|
|
8250
|
-
readonly kind?: MagicBarActionKind;
|
|
8251
|
-
/** Dimmed (`opacity .38`), NEVER hidden — a vanishing action teaches the user nothing. */
|
|
8252
|
-
readonly disabled?: boolean;
|
|
8253
|
-
/**
|
|
8254
|
-
* Tooltip override while disabled. Absent is the normal case: the renderer
|
|
8255
|
-
* auto-suffixes the resolved label ("… — select an item first"). Resolution
|
|
8256
|
-
* and the connector phrasing are the renderer's job precisely because they are
|
|
8257
|
-
* locale work, and this store holds keys rather than text.
|
|
8258
|
-
*/
|
|
8259
|
-
readonly disabledTipKey?: string;
|
|
8260
|
-
/** Params for {@link disabledTipKey}. */
|
|
8261
|
-
readonly disabledTipParams?: MagicBarTextParams;
|
|
8262
|
-
/** Tooltip override while enabled. Absent → the renderer uses `labelKey`. */
|
|
8263
|
-
readonly tipKey?: string;
|
|
8264
|
-
/** Params for {@link tipKey}. */
|
|
8265
|
-
readonly tipParams?: MagicBarTextParams;
|
|
8266
|
-
/**
|
|
8267
|
-
* Semantic colour. Default `'default'`; `'danger'` is the ONLY thing that makes
|
|
8268
|
-
* an icon red (D7), `'success'` the green completed-toggle treatment.
|
|
8876
|
+
* Recomputes when either the registry or `liveAppIds` changes. Pass a
|
|
8877
|
+
* `Signal<ReadonlySet<string>>` from the host's app-registry for reactive
|
|
8878
|
+
* re-sorting. **Always returns the full registry** — see the type doc on
|
|
8879
|
+
* {@link LookupRegistration.scope} for why this differs from
|
|
8880
|
+
* {@link AgentCommandRegistry.visible}.
|
|
8269
8881
|
*/
|
|
8270
|
-
readonly
|
|
8271
|
-
/** `aria-pressed` for `kind: 'toggle'`. */
|
|
8272
|
-
readonly pressed?: boolean;
|
|
8273
|
-
/** Small accent dot — a non-default filter/sort is active. */
|
|
8274
|
-
readonly badgeDot?: boolean;
|
|
8882
|
+
visible(liveAppIds: ReadonlySet<string> | Signal<ReadonlySet<string>>): Signal<readonly LookupRegistration[]>;
|
|
8275
8883
|
/**
|
|
8276
|
-
*
|
|
8277
|
-
*
|
|
8278
|
-
*
|
|
8884
|
+
* Register one lookup. Returns a handle whose `dispose()` removes the row by
|
|
8885
|
+
* `entity`. A later re-registration of the same entity makes the original
|
|
8886
|
+
* handle's `dispose()` a no-op (the newer registration owns the row).
|
|
8279
8887
|
*/
|
|
8280
|
-
|
|
8281
|
-
}
|
|
8282
|
-
/** What a publisher supplies for one action. */
|
|
8283
|
-
interface MagicBarAction extends MagicBarActionSpec {
|
|
8284
|
-
readonly menu?: MagicBarRadioMenu;
|
|
8888
|
+
register(lookup: LookupRegistration): LookupHandle;
|
|
8285
8889
|
/**
|
|
8286
|
-
*
|
|
8287
|
-
*
|
|
8288
|
-
*
|
|
8289
|
-
* handler it has always been.
|
|
8890
|
+
* Bulk register. Rolls back on a duplicate entity WITHIN the input batch
|
|
8891
|
+
* (throws before any row lands). Cross-batch duplicates against existing rows
|
|
8892
|
+
* follow the standard "latest wins" rule and do NOT trigger rollback.
|
|
8290
8893
|
*/
|
|
8291
|
-
readonly
|
|
8292
|
-
}
|
|
8293
|
-
/**
|
|
8294
|
-
* What the shell renders. `run()` always exists and always dispatches to the
|
|
8295
|
-
* publisher's LATEST handler for this id — including after a re-publish the
|
|
8296
|
-
* registry deliberately did not propagate (see `magic-bar-projection.ts`).
|
|
8297
|
-
*/
|
|
8298
|
-
interface MagicBarActionView extends MagicBarActionSpec {
|
|
8299
|
-
readonly menu: MagicBarRadioMenuView | null;
|
|
8894
|
+
registerAll(lookups: readonly LookupRegistration[]): LookupHandle;
|
|
8300
8895
|
/**
|
|
8301
|
-
*
|
|
8302
|
-
*
|
|
8303
|
-
* ## Why it carries the trigger element
|
|
8304
|
-
* An action that opens a POPOVER the publisher owns — the canonical case is a
|
|
8305
|
-
* listing screen's advanced-filter panel — has to position that popover under
|
|
8306
|
-
* the button the user just pressed. The publisher cannot find that button:
|
|
8307
|
-
* embedded, it is painted by `fly-magic-actions` inside the shell's top-bar
|
|
8308
|
-
* pill, in the shell's DOM, several stacking contexts and one federation
|
|
8309
|
-
* boundary away from the remote that published the action. Before this argument
|
|
8310
|
-
* existed, PPM's projects register had to anchor its panel to its own page
|
|
8311
|
-
* header instead, which put the panel in the middle of the window while the
|
|
8312
|
-
* button that opened it sat in the chrome above — an affordance with no visible
|
|
8313
|
-
* relationship to its own trigger.
|
|
8896
|
+
* Resolve a deep-link anchor to a concrete launch target.
|
|
8314
8897
|
*
|
|
8315
|
-
*
|
|
8316
|
-
*
|
|
8317
|
-
*
|
|
8318
|
-
*
|
|
8319
|
-
*
|
|
8320
|
-
*
|
|
8321
|
-
*
|
|
8898
|
+
* `kind` is the dotted `<appId>.<entity>` token the agents backend emits
|
|
8899
|
+
* inside `flyos:<kind>/<id>` chat-answer anchors — the same entity-kind
|
|
8900
|
+
* vocabulary as drag-payload kinds and `ref` parts. Returns
|
|
8901
|
+
* `{ appId, route }` when a registered lookup for that `(appId, entity)`
|
|
8902
|
+
* pair carries a {@link LookupDescriptor.deepLinkRoute} template; `null`
|
|
8903
|
+
* otherwise (unknown entity, app mismatch, or no template — e.g. the
|
|
8904
|
+
* owning app isn't installed) so the caller renders plain text rather than
|
|
8905
|
+
* a dead link.
|
|
8322
8906
|
*
|
|
8323
|
-
*
|
|
8324
|
-
*
|
|
8325
|
-
*
|
|
8326
|
-
*
|
|
8327
|
-
|
|
8328
|
-
|
|
8907
|
+
* `appId` and `entity` are both dot-free by their own grammars, so the
|
|
8908
|
+
* FIRST dot is the unambiguous split point; a dotless `kind` can't carry an
|
|
8909
|
+
* app and never resolves. The template's single `{id}` placeholder is
|
|
8910
|
+
* substituted URL-encoded.
|
|
8911
|
+
*/
|
|
8912
|
+
resolveDeepLink(kind: string, id: string): {
|
|
8913
|
+
readonly appId: string;
|
|
8914
|
+
readonly route: string;
|
|
8915
|
+
} | null;
|
|
8916
|
+
/**
|
|
8917
|
+
* Resolve a deep-link target from a bare `(entity, id)` pair — the shape a
|
|
8918
|
+
* `/lookup` ref carries (it has no `<appId>.<entity>` kind token; the owning
|
|
8919
|
+
* app is implicit in the registered descriptor). `entity` is the registry's
|
|
8920
|
+
* unique storage key, so it identifies the descriptor unambiguously without
|
|
8921
|
+
* an app prefix.
|
|
8329
8922
|
*
|
|
8330
|
-
*
|
|
8331
|
-
*
|
|
8332
|
-
*
|
|
8333
|
-
*
|
|
8334
|
-
*
|
|
8923
|
+
* Returns `{ appId, route }` (the descriptor's {@link LookupDescriptor.appId}
|
|
8924
|
+
* / affinity `scope.appId` as the owner, `{id}` substituted URL-encoded) when
|
|
8925
|
+
* a matching descriptor carries a {@link LookupDescriptor.deepLinkRoute};
|
|
8926
|
+
* `null` otherwise (unknown entity, no template, or the owning app has since
|
|
8927
|
+
* unregistered) so callers render plain text rather than a dead link — the
|
|
8928
|
+
* same graceful-degrade contract as {@link resolveDeepLink}.
|
|
8335
8929
|
*/
|
|
8336
|
-
|
|
8337
|
-
|
|
8338
|
-
|
|
8339
|
-
|
|
8340
|
-
|
|
8341
|
-
|
|
8342
|
-
|
|
8343
|
-
|
|
8344
|
-
|
|
8345
|
-
|
|
8346
|
-
|
|
8347
|
-
|
|
8348
|
-
}
|
|
8349
|
-
interface MagicBarGroupView extends MagicBarGroupSpec {
|
|
8350
|
-
readonly items: readonly MagicBarActionView[];
|
|
8930
|
+
resolveDeepLinkForEntity(entity: string, id: string): {
|
|
8931
|
+
readonly appId: string;
|
|
8932
|
+
readonly route: string;
|
|
8933
|
+
} | null;
|
|
8934
|
+
/** Tear down by entity. Idempotent. */
|
|
8935
|
+
unregister(entity: string): void;
|
|
8936
|
+
/** Monotonic counter; identifies which registration call currently owns each entity. */
|
|
8937
|
+
private _generation;
|
|
8938
|
+
/** entity → generation. Lets a stale handle's `dispose()` no-op after replacement. */
|
|
8939
|
+
private readonly _owners;
|
|
8940
|
+
static ɵfac: _angular_core.ɵɵFactoryDeclaration<AgentLookupRegistry, never>;
|
|
8941
|
+
static ɵprov: _angular_core.ɵɵInjectableDeclaration<AgentLookupRegistry>;
|
|
8351
8942
|
}
|
|
8943
|
+
|
|
8352
8944
|
/**
|
|
8353
|
-
*
|
|
8354
|
-
*
|
|
8945
|
+
* Singleton registry of chip-renderer components and keyboard-alternative draggable
|
|
8946
|
+
* items, keyed by `kind` and `appId`.
|
|
8355
8947
|
*
|
|
8356
|
-
*
|
|
8357
|
-
*
|
|
8948
|
+
* Like {@link AgentCommandRegistry}, this lives in the DS so it crosses the federation
|
|
8949
|
+
* boundary as a single instance. Hosts (the shell `<fly-agent-input>`) lookup
|
|
8950
|
+
* renderers; remotes register them.
|
|
8951
|
+
*
|
|
8952
|
+
* Renderer lookup is `O(n)` over the registered list — the registry is small (one or
|
|
8953
|
+
* two entries per app) and lookups happen on drop, not per frame.
|
|
8954
|
+
*
|
|
8955
|
+
* Draggable storage is per-`appId` writable signal cached in a Map, so each `appId`
|
|
8956
|
+
* gets a stable {@link Signal} reference across reads (callers can `===`-compare).
|
|
8358
8957
|
*/
|
|
8359
|
-
|
|
8360
|
-
|
|
8361
|
-
|
|
8362
|
-
|
|
8363
|
-
readonly placeholderParams?: MagicBarTextParams;
|
|
8958
|
+
declare class AgentDropRegistry {
|
|
8959
|
+
private readonly _renderers;
|
|
8960
|
+
/** Per-appId writable store for draggables. Read-only mirror returned to callers. */
|
|
8961
|
+
private readonly _draggablesByApp;
|
|
8364
8962
|
/**
|
|
8365
|
-
*
|
|
8366
|
-
*
|
|
8367
|
-
*
|
|
8368
|
-
* Exists because a view can arrive **already filtered**: a deep link carrying
|
|
8369
|
-
* `?q=…`, a restored session, a filter applied from a detail pane. Without it the
|
|
8370
|
-
* box renders empty over a visibly filtered list, and the user is looking at a
|
|
8371
|
-
* contradiction the chrome cannot explain.
|
|
8372
|
-
*
|
|
8373
|
-
* ## Why it is not called `query`
|
|
8374
|
-
* {@link MagicBarSearchView} — which extends this interface — already declares
|
|
8375
|
-
* `query(text: string): void`, the late-bound invoker. A `query?: string` here
|
|
8376
|
-
* would make that view an illegal extension (TS2430: `(text: string) => void` is
|
|
8377
|
-
* not assignable to `string | undefined`), and the only other way out — renaming
|
|
8378
|
-
* the invoker — removes a member of a shipped exported interface, which is a
|
|
8379
|
-
* ds-compat MAJOR (rule 7) and forks the federation singleton for every remote.
|
|
8380
|
-
* So the field takes the name that pairs with the invoker instead of colliding
|
|
8381
|
-
* with it: `queryText` is the text, `query()` submits it.
|
|
8382
|
-
*
|
|
8383
|
-
* ## Precedence — this is a SEED, not a controlled value
|
|
8384
|
-
* The field's live text is owned by the **shell**, because the user types into
|
|
8385
|
-
* it. This field is the publisher's chance to move it, and the shell adopts the
|
|
8386
|
-
* published value exactly three times:
|
|
8387
|
-
*
|
|
8388
|
-
* 1. the first time it binds this view,
|
|
8389
|
-
* 2. when {@link MagicBarContribution.viewKey} changes (reset-on-navigate — the
|
|
8390
|
-
* previous view's query must not survive into the next one), and
|
|
8391
|
-
* 3. when the published value **itself changes** from the one previously
|
|
8392
|
-
* published.
|
|
8393
|
-
*
|
|
8394
|
-
* A re-publish carrying an UNCHANGED `queryText` never touches what the user has
|
|
8395
|
-
* typed. That third clause is the whole rule: the dominant re-publish is
|
|
8396
|
-
* `disabled: !hasSelection` flipping on a selection change, and a shell that
|
|
8397
|
-
* re-read `queryText` on every emitted view would revert a keystroke every time
|
|
8398
|
-
* the user selected a row mid-search — the classic controlled-input bug. The rule
|
|
8399
|
-
* is authored once, as {@link magicBarSearchText}, so no renderer re-derives it.
|
|
8400
|
-
*
|
|
8401
|
-
* `undefined` and `''` are **different** and the difference is load-bearing:
|
|
8402
|
-
* absent means "this view does not manage the field" (nothing is ever forced),
|
|
8403
|
-
* `''` means "clear it". Both the fingerprint and the seed comparison distinguish
|
|
8404
|
-
* them.
|
|
8963
|
+
* Look up the chip-renderer component class for a `kind`. The newest registration for
|
|
8964
|
+
* a given `kind` wins, regardless of `appId` — we scan the list in reverse so a later
|
|
8965
|
+
* `register` call shadows an earlier one for the same `kind`.
|
|
8405
8966
|
*
|
|
8406
|
-
*
|
|
8407
|
-
*
|
|
8408
|
-
* is harmless (the seed changes to text the field already shows). A publisher
|
|
8409
|
-
* that mirrors it back **debounced** is not: typing "abc" then publishing
|
|
8410
|
-
* `queryText: 'a'` 300 ms later is, by rule 3, a genuine publisher-initiated
|
|
8411
|
-
* change, and the field snaps back to "a". Publish here only for state the view
|
|
8412
|
-
* owns independently of the field.
|
|
8967
|
+
* Returns `null` when no renderer is registered; the host falls back to a generic
|
|
8968
|
+
* `plainTextFallback` chip.
|
|
8413
8969
|
*/
|
|
8414
|
-
|
|
8970
|
+
rendererFor(kind: string): Type<AgentChipHostInputs> | null;
|
|
8415
8971
|
/**
|
|
8416
|
-
*
|
|
8972
|
+
* Register a renderer for a `(kind, appId)` pair. Re-registering the same pair
|
|
8973
|
+
* replaces the prior entry; the disposal handle for the prior registration becomes
|
|
8974
|
+
* a no-op.
|
|
8417
8975
|
*
|
|
8418
|
-
*
|
|
8419
|
-
*
|
|
8420
|
-
* contribution over a cosmetic hint (leaving the previous view's actions in the
|
|
8421
|
-
* chrome), and mobile ignores the field entirely, so there is no single range to
|
|
8422
|
-
* enforce. `fly-magic-actions` clamps to the design range at paint time and is
|
|
8423
|
-
* the only place that decides what an out-of-range or non-finite value means.
|
|
8976
|
+
* Returns a {@link AgentCommandHandle} (re-used to keep the disposable shape uniform
|
|
8977
|
+
* across registries) whose `dispose()` removes this exact registration.
|
|
8424
8978
|
*/
|
|
8425
|
-
|
|
8426
|
-
/**
|
|
8427
|
-
|
|
8979
|
+
register<T = unknown>(reg: AgentDropRendererRegistration<T>): AgentCommandHandle;
|
|
8980
|
+
/**
|
|
8981
|
+
* Apps publish their live "draggable from focused window" set so the keyboard
|
|
8982
|
+
* "Attach from app…" menu can offer them. Hosts call this each time the user-visible
|
|
8983
|
+
* draggable list changes; passing an empty array clears the entry for this `appId`.
|
|
8984
|
+
*/
|
|
8985
|
+
publishDraggables(appId: string, items: readonly AgentDraggableItem[]): void;
|
|
8986
|
+
/**
|
|
8987
|
+
* Reactive read of the draggable set published for `appId`. Empty when none. The
|
|
8988
|
+
* returned signal is stable across calls (cached by `appId`), so consumers can use
|
|
8989
|
+
* it as a stable input to `computed()`.
|
|
8990
|
+
*/
|
|
8991
|
+
draggablesFor(appId: string): Signal<readonly AgentDraggableItem[]>;
|
|
8992
|
+
/** Lazy-init the per-appId writable bucket. Returns the writable handle for internal use. */
|
|
8993
|
+
private bucketFor;
|
|
8994
|
+
private _generation;
|
|
8995
|
+
private readonly _owners;
|
|
8996
|
+
static ɵfac: _angular_core.ɵɵFactoryDeclaration<AgentDropRegistry, never>;
|
|
8997
|
+
static ɵprov: _angular_core.ɵɵInjectableDeclaration<AgentDropRegistry>;
|
|
8998
|
+
}
|
|
8999
|
+
|
|
9000
|
+
/**
|
|
9001
|
+
* Imperative action published by an app, consumed by the agent panel.
|
|
9002
|
+
*
|
|
9003
|
+
* Re-uses {@link AgentDragPayload} as the wire envelope so a dragged item
|
|
9004
|
+
* and a programmatic "Explain" click are byte-for-byte the same shape —
|
|
9005
|
+
* renderers, validators, and serialisation paths never fork on transport.
|
|
9006
|
+
*
|
|
9007
|
+
* Adding a verb is a minor DS bump (consumers ignore unknown verbs in
|
|
9008
|
+
* their `switch`). Removing one is a major DS bump.
|
|
9009
|
+
*/
|
|
9010
|
+
type AgentActionVerb = 'explain' | 'why-empty' | 'compose-query' | 'compare' | 'summarize';
|
|
9011
|
+
/**
|
|
9012
|
+
* Whether the agent panel sends the staged payload immediately or stages
|
|
9013
|
+
* the chip for the user to edit and send manually.
|
|
9014
|
+
*
|
|
9015
|
+
* Phase 1 (DS v2.6.0) supports `'stage'` only. Dispatching with `'auto'`
|
|
9016
|
+
* throws {@link AgentActionUnsupportedDispatchError} so callers don't
|
|
9017
|
+
* silently fail. `'auto'` lands once `AgentInputComponent.programmaticSubmit`
|
|
9018
|
+
* is exposed and reviewed against the input's state machine.
|
|
9019
|
+
*/
|
|
9020
|
+
type AgentActionDispatch = 'auto' | 'stage';
|
|
9021
|
+
interface AgentAction<T = unknown> {
|
|
9022
|
+
/** Intent the agent should apply to {@link payload}. */
|
|
9023
|
+
readonly verb: AgentActionVerb;
|
|
9024
|
+
/** The wire envelope. Validated against {@link validateAgentPayload}'s
|
|
9025
|
+
* size caps before the bus fans it out. */
|
|
9026
|
+
readonly payload: AgentDragPayload<T>;
|
|
9027
|
+
/** Optional slash command id to bind before send (e.g. `'explain-report'`).
|
|
9028
|
+
* Phase 1 captures this for telemetry only — actual binding lands when
|
|
9029
|
+
* the input's programmatic-send API ships. An unknown id is dropped
|
|
9030
|
+
* silently with a console warning, the chip still arrives. */
|
|
9031
|
+
readonly autoCommandId?: string;
|
|
9032
|
+
/** Phase 1 supports `'stage'` only. See {@link AgentActionDispatch}. */
|
|
9033
|
+
readonly dispatch: AgentActionDispatch;
|
|
9034
|
+
/** Source DOM rect for the FLIP entry animation. Omit to skip the
|
|
9035
|
+
* animation (e.g. dispatching from a keyboard shortcut with no anchor). */
|
|
9036
|
+
readonly originRect?: DOMRect;
|
|
9037
|
+
/** Optional HTML snippet rendered inside the flight ghost. Callers are
|
|
9038
|
+
* responsible for escaping untrusted text — the bus does not sanitise.
|
|
9039
|
+
* Defaults (when omitted) to a strong-wrapped escape of the payload's
|
|
9040
|
+
* `plainTextFallback` rendered by the panel host. */
|
|
9041
|
+
readonly originPreviewHtml?: string;
|
|
8428
9042
|
}
|
|
8429
|
-
|
|
8430
|
-
|
|
8431
|
-
|
|
8432
|
-
|
|
8433
|
-
|
|
8434
|
-
|
|
8435
|
-
|
|
8436
|
-
|
|
8437
|
-
|
|
8438
|
-
readonly onOpenFilters?: (trigger?: HTMLElement) => void;
|
|
9043
|
+
/**
|
|
9044
|
+
* Thrown synchronously by {@link AgentActionBus.dispatch} when a caller
|
|
9045
|
+
* supplies a dispatch mode this DS version doesn't implement yet. Catching
|
|
9046
|
+
* by class name lets a forward-compatible caller fall back to `'stage'`
|
|
9047
|
+
* without depending on instanceof across federation boundaries.
|
|
9048
|
+
*/
|
|
9049
|
+
declare class AgentActionUnsupportedDispatchError extends Error {
|
|
9050
|
+
readonly dispatch: AgentActionDispatch;
|
|
9051
|
+
constructor(dispatch: AgentActionDispatch);
|
|
8439
9052
|
}
|
|
8440
|
-
|
|
8441
|
-
|
|
8442
|
-
|
|
9053
|
+
|
|
9054
|
+
/**
|
|
9055
|
+
* Imperative sibling to {@link AgentCommandRegistry} / {@link AgentDropRegistry}.
|
|
9056
|
+
*
|
|
9057
|
+
* Apps call {@link dispatch} to push a typed {@link AgentAction} onto the bus;
|
|
9058
|
+
* the agent panel subscribes once at construct and routes by verb. The bus
|
|
9059
|
+
* itself is a thin pass-through — it does NOT decide UI behaviour. The
|
|
9060
|
+
* subscriber (agent-panel) owns: showing the panel, staging the chip,
|
|
9061
|
+
* triggering the flight animation, and binding the command. This keeps the
|
|
9062
|
+
* DS free of host policy.
|
|
9063
|
+
*
|
|
9064
|
+
* Federation-safe: `providedIn: 'root'` + `sharedMappings: ['@flyos/design-system']`
|
|
9065
|
+
* give every federated remote the same singleton, so a remote's "Explain"
|
|
9066
|
+
* button reaches the host's panel without any cross-bundle wiring.
|
|
9067
|
+
*
|
|
9068
|
+
* Validation runs synchronously inside `dispatch` so a caller that sends an
|
|
9069
|
+
* oversize payload sees the throw at their site, not on the subscriber. The
|
|
9070
|
+
* subscriber therefore never has to defend against malformed envelopes.
|
|
9071
|
+
*/
|
|
9072
|
+
declare class AgentActionBus {
|
|
9073
|
+
private readonly _actions$;
|
|
9074
|
+
/** Hot stream of actions in dispatch order. Subscribers receive only
|
|
9075
|
+
* actions dispatched AFTER they subscribe — late subscribers see nothing
|
|
9076
|
+
* retroactively. Use {@link lastAction} for the latest snapshot. */
|
|
9077
|
+
readonly actions$: Observable<AgentAction>;
|
|
9078
|
+
/** Most recent action — for DevTools, smoke tests, and late-subscriber
|
|
9079
|
+
* catch-up. Null until the first successful dispatch. */
|
|
9080
|
+
readonly lastAction: _angular_core.WritableSignal<AgentAction<unknown> | null>;
|
|
8443
9081
|
/**
|
|
8444
|
-
*
|
|
8445
|
-
*
|
|
8446
|
-
* {@link
|
|
8447
|
-
*
|
|
9082
|
+
* The action currently being processed by the subscriber, or null when
|
|
9083
|
+
* none. Set by {@link dispatch} immediately before emitting on
|
|
9084
|
+
* {@link actions$}; cleared by the subscriber via {@link settle} once
|
|
9085
|
+
* it finishes its handler (success or fail). Lets the dispatcher render
|
|
9086
|
+
* a busy state on the originating control — e.g. a card swapping its
|
|
9087
|
+
* sparkle icon for a spinner while the agent panel mints the optimistic
|
|
9088
|
+
* thread and starts the request. Identity check (`bus.inFlight() === act`)
|
|
9089
|
+
* is the panel-side contract; dispatchers usually project to a stable id
|
|
9090
|
+
* inside the payload (e.g. <c>reportId</c>) to scope busy-state visually.
|
|
9091
|
+
*
|
|
9092
|
+
* If multiple dispatches race, the latest wins — the prior in-flight
|
|
9093
|
+
* action is dropped on the floor here (the panel may still handle it,
|
|
9094
|
+
* but the dispatcher's busy indicator follows the newer action). Apps
|
|
9095
|
+
* that need stricter single-flight semantics should guard at the call
|
|
9096
|
+
* site (the agent-panel's <c>_pendingTempThreadId</c> already does so
|
|
9097
|
+
* for the explain verb).
|
|
8448
9098
|
*/
|
|
8449
|
-
|
|
9099
|
+
readonly inFlight: _angular_core.WritableSignal<AgentAction<unknown> | null>;
|
|
8450
9100
|
/**
|
|
8451
|
-
*
|
|
8452
|
-
*
|
|
8453
|
-
*
|
|
8454
|
-
*
|
|
9101
|
+
* Push an action onto the bus.
|
|
9102
|
+
*
|
|
9103
|
+
* Throws synchronously when:
|
|
9104
|
+
* - `dispatch === 'auto'` (not implemented in this DS version) — see
|
|
9105
|
+
* {@link AgentActionUnsupportedDispatchError}.
|
|
9106
|
+
* - the payload fails {@link validateAgentPayload} (oversize, invalid
|
|
9107
|
+
* version, invalid kind). The error message carries the field path
|
|
9108
|
+
* so the caller can fix the offending field.
|
|
9109
|
+
*
|
|
9110
|
+
* Subscribers see the action via {@link actions$} on the next tick of
|
|
9111
|
+
* the Subject; the {@link lastAction} signal updates synchronously
|
|
9112
|
+
* before the Subject emits so an effect reading both stays consistent.
|
|
8455
9113
|
*/
|
|
8456
|
-
|
|
8457
|
-
}
|
|
8458
|
-
/**
|
|
8459
|
-
* One view's complete claim on the magic bar.
|
|
8460
|
-
*
|
|
8461
|
-
* Identity (`appId` / `windowId`) is deliberately absent: it belongs to the
|
|
8462
|
-
* {@link MagicBarPublisher} that was minted for this owner, so a later publish
|
|
8463
|
-
* cannot re-target another app's slot.
|
|
8464
|
-
*/
|
|
8465
|
-
interface MagicBarContribution {
|
|
9114
|
+
dispatch<T>(action: AgentAction<T>): void;
|
|
8466
9115
|
/**
|
|
8467
|
-
*
|
|
8468
|
-
*
|
|
8469
|
-
*
|
|
9116
|
+
* Subscriber contract: call after the handler for {@link inFlight}
|
|
9117
|
+
* completes (success or fail). Only clears {@link inFlight} if it still
|
|
9118
|
+
* points at the passed action — a no-op when a later dispatch already
|
|
9119
|
+
* superseded it. Pass the same action reference the subscriber received
|
|
9120
|
+
* from {@link actions$}; identity is the gate.
|
|
8470
9121
|
*/
|
|
8471
|
-
|
|
8472
|
-
readonly search?: MagicBarSearch | null;
|
|
8473
|
-
/** Ordered clusters, separator-joined. */
|
|
8474
|
-
readonly groups?: readonly MagicBarGroup[];
|
|
8475
|
-
/** The accent-filled CTA ("New task", "Add signal"). */
|
|
8476
|
-
readonly primary?: MagicBarAction | null;
|
|
9122
|
+
settle(action: AgentAction): void;
|
|
8477
9123
|
/**
|
|
8478
|
-
*
|
|
8479
|
-
*
|
|
9124
|
+
* Semantic alias of {@link settle} for explicit user-driven cancellation —
|
|
9125
|
+
* e.g. a future "Stop" button in the agent input tray, or a dispatcher
|
|
9126
|
+
* teardown that wants to abandon its own in-flight action. Identical
|
|
9127
|
+
* runtime behaviour (identity check + clear), but the two-method surface
|
|
9128
|
+
* lets the UI distinguish "handler finished" from "user said no" in
|
|
9129
|
+
* telemetry / logs without sniffing a "reason" parameter.
|
|
8480
9130
|
*
|
|
8481
|
-
*
|
|
8482
|
-
*
|
|
8483
|
-
* production must source these from manifests instead of the mock's hardcoded
|
|
8484
|
-
* `{ title, note, prompt }` triples. Duplicating that model here would fork the
|
|
8485
|
-
* palette and reintroduce hardcoded prompt text. Unknown ids are dropped by the
|
|
8486
|
-
* resolver; an empty list leaves the shell's affinity ranking in charge.
|
|
9131
|
+
* Pass the same action reference returned from {@link inFlight} or held
|
|
9132
|
+
* by the dispatcher; identity is the gate.
|
|
8487
9133
|
*/
|
|
8488
|
-
|
|
8489
|
-
|
|
8490
|
-
|
|
8491
|
-
}
|
|
8492
|
-
/** The shell-facing projection of a contribution. See `magic-bar-projection.ts`. */
|
|
8493
|
-
interface MagicBarView {
|
|
8494
|
-
readonly appId: string;
|
|
8495
|
-
readonly windowId?: string;
|
|
8496
|
-
/** {@link magicBarOwnerKey} of the publisher. */
|
|
8497
|
-
readonly ownerKey: string;
|
|
8498
|
-
readonly viewKey: string;
|
|
8499
|
-
readonly search: MagicBarSearchView | null;
|
|
8500
|
-
readonly groups: readonly MagicBarGroupView[];
|
|
8501
|
-
readonly primary: MagicBarActionView | null;
|
|
8502
|
-
readonly quickCommandIds: readonly string[];
|
|
8503
|
-
readonly overflow: readonly MagicBarActionView[];
|
|
9134
|
+
cancel(action: AgentAction): void;
|
|
9135
|
+
static ɵfac: _angular_core.ɵɵFactoryDeclaration<AgentActionBus, never>;
|
|
9136
|
+
static ɵprov: _angular_core.ɵɵInjectableDeclaration<AgentActionBus>;
|
|
8504
9137
|
}
|
|
9138
|
+
|
|
8505
9139
|
/**
|
|
8506
|
-
*
|
|
8507
|
-
*
|
|
8508
|
-
*
|
|
8509
|
-
*
|
|
8510
|
-
*
|
|
8511
|
-
*
|
|
9140
|
+
* FLIP-style entry animation for payloads landing in the agent panel.
|
|
9141
|
+
*
|
|
9142
|
+
* Pure DOM + Web Animations API — no Chart.js, no Angular animations module,
|
|
9143
|
+
* no CSS transitions racing layout. Honours `prefers-reduced-motion`: the
|
|
9144
|
+
* ghost is appended then removed without animating when the user asked for
|
|
9145
|
+
* less motion (so DOM side-effects stay consistent).
|
|
9146
|
+
*
|
|
9147
|
+
* Lifecycle:
|
|
9148
|
+
* 1. The agent panel calls {@link registerTarget} in `ngAfterViewInit`
|
|
9149
|
+
* with its header element.
|
|
9150
|
+
* 2. A source app dispatches an `AgentAction` carrying an `originRect`
|
|
9151
|
+
* from `getBoundingClientRect()` on the click target.
|
|
9152
|
+
* 3. The bus subscriber calls {@link flyInto} with that rect.
|
|
9153
|
+
* 4. The animator creates a fixed-position ghost at the origin, animates
|
|
9154
|
+
* transform + opacity toward the registered target's rect, then
|
|
9155
|
+
* removes itself on `onfinish` / `oncancel`.
|
|
9156
|
+
*
|
|
9157
|
+
* Uses `getBoundingClientRect()` (physical viewport coords) so the animation
|
|
9158
|
+
* is RTL-correct without inset-inline math — the rect already encodes the
|
|
9159
|
+
* physical position regardless of `dir`.
|
|
9160
|
+
*
|
|
9161
|
+
* The 900 ms duration and easing curve are deliberately hardcoded — making
|
|
9162
|
+
* them configurable surfaces an API the host can't usefully tune without
|
|
9163
|
+
* understanding motion design as a whole.
|
|
8512
9164
|
*/
|
|
8513
|
-
|
|
8514
|
-
|
|
9165
|
+
declare class AgentFlightAnimator {
|
|
9166
|
+
/** Hardcoded — see class doc. */
|
|
9167
|
+
private static readonly DURATION_MS;
|
|
9168
|
+
private static readonly EASING;
|
|
9169
|
+
/** Floor the target/source scale ratio so a tiny target rect doesn't
|
|
9170
|
+
* collapse the ghost to invisibility before the animation finishes. */
|
|
9171
|
+
private static readonly MIN_SCALE;
|
|
9172
|
+
private targetEl;
|
|
9173
|
+
/** Called by the panel host to publish where flights should land. Pass
|
|
9174
|
+
* `null` on destroy so a re-mounted panel doesn't leave the animator
|
|
9175
|
+
* pointing at a detached node. */
|
|
9176
|
+
registerTarget(el: HTMLElement | null): void;
|
|
8515
9177
|
/**
|
|
8516
|
-
*
|
|
8517
|
-
*
|
|
9178
|
+
* Animate a ghost element from {@link from} to the registered target's
|
|
9179
|
+
* rect. No-ops when:
|
|
9180
|
+
* - no target is registered (silent — panel may not be mounted yet)
|
|
9181
|
+
* - running outside a browser (SSR safety)
|
|
9182
|
+
* - the user has `prefers-reduced-motion: reduce` set (DOM is still
|
|
9183
|
+
* touched so callers see consistent side-effects, but no animation
|
|
9184
|
+
* runs)
|
|
8518
9185
|
*
|
|
8519
|
-
*
|
|
8520
|
-
*
|
|
8521
|
-
* cannot `dispose()` the newer one out of the slot, but it *can* still take the
|
|
8522
|
-
* slot back by publishing. Symmetry would need a "newest publisher wins" rule
|
|
8523
|
-
* enforced on write, which would make the first publish of a replacement
|
|
8524
|
-
* publisher silently drop whenever two live views briefly share a key. The
|
|
8525
|
-
* exposure is bounded: two live publishers on one owner key only happen while a
|
|
8526
|
-
* view is being replaced in place, and the loser re-publishes on its next
|
|
8527
|
-
* selection change. The unbounded case — a publisher that outlives its window —
|
|
8528
|
-
* is closed by `clear()`'s tombstone, not by write ordering.
|
|
8529
|
-
*/
|
|
8530
|
-
publish(contribution: MagicBarContribution): void;
|
|
8531
|
-
/**
|
|
8532
|
-
* Release the slot. Idempotent, and a no-op if another publisher has since
|
|
8533
|
-
* taken this owner key — the same stale-handle rule the sibling registries use.
|
|
9186
|
+
* The ghost is appended to `document.body` (not the panel) so a parent
|
|
9187
|
+
* `overflow: hidden` on the panel can't clip the flight path.
|
|
8534
9188
|
*/
|
|
8535
|
-
|
|
9189
|
+
flyInto(from: DOMRect, opts?: {
|
|
9190
|
+
previewHtml?: string;
|
|
9191
|
+
}): void;
|
|
9192
|
+
static ɵfac: _angular_core.ɵɵFactoryDeclaration<AgentFlightAnimator, never>;
|
|
9193
|
+
static ɵprov: _angular_core.ɵɵInjectableDeclaration<AgentFlightAnimator>;
|
|
8536
9194
|
}
|
|
8537
9195
|
|
|
8538
9196
|
/**
|
|
@@ -8813,6 +9471,36 @@ interface MagicBarSearchSeed {
|
|
|
8813
9471
|
*/
|
|
8814
9472
|
declare function magicBarSearchText(previous: MagicBarSearchSeed | null, next: MagicBarSearchSeed): string | null;
|
|
8815
9473
|
|
|
9474
|
+
/**
|
|
9475
|
+
* Order one group's items the way every FlyOS bar orders them.
|
|
9476
|
+
*
|
|
9477
|
+
* **Icon-only actions occupy the outer edge of the flow — the right in LTR — in the precedence
|
|
9478
|
+
* Add, Delete, Edit reading inward; labelled (icon+label) actions sit inside them.**
|
|
9479
|
+
*
|
|
9480
|
+
* The outer edge is where the hand and the eye finish, so it belongs to the actions that need no
|
|
9481
|
+
* reading: a bare glyph is fastest to hit and slowest to identify, and putting the glyphs where
|
|
9482
|
+
* they are found by position rather than by reading is what makes that trade pay. A labelled
|
|
9483
|
+
* action is identified by its text wherever it sits, so it gives the edge up.
|
|
9484
|
+
*
|
|
9485
|
+
* Order is expressed as FLOW order, never as physical left/right: the bar mirrors under RTL, so
|
|
9486
|
+
* "outermost" becomes the left edge in `ar`/`ur` automatically. Encoding it as a physical side
|
|
9487
|
+
* would be a bug in three of this platform's four locales.
|
|
9488
|
+
*
|
|
9489
|
+
* Stable within each band — callers keep authoring items in whatever order reads best in source,
|
|
9490
|
+
* and two labelled actions stay in the order they were written (PPM's "Promote to schedule" stays
|
|
9491
|
+
* after "Add backlog task").
|
|
9492
|
+
*
|
|
9493
|
+
* ## Why this lives in the design system
|
|
9494
|
+
* It shipped first inside PPM (`ppm/shared/magic-bar-order.util.ts`) and
|
|
9495
|
+
* `skills/shell-magic-bar-views.md` §7 named that file as the reference implementation —
|
|
9496
|
+
* which is exactly the shape of a rule that is about to be copy-pasted into the next External App.
|
|
9497
|
+
* The ordering is a property of the BAR, not of any one app: the same renderer paints every
|
|
9498
|
+
* contribution, so two apps disagreeing about it is a platform-visible inconsistency, not a local
|
|
9499
|
+
* style choice. Same reasoning as {@link magicBarSearchText} — a documented-but-unimplemented rule
|
|
9500
|
+
* gets re-derived per consumer, and the copies disagree on precisely the case that is hard to see.
|
|
9501
|
+
*/
|
|
9502
|
+
declare function orderMagicBarItems(items: readonly MagicBarAction[]): MagicBarAction[];
|
|
9503
|
+
|
|
8816
9504
|
/**
|
|
8817
9505
|
* Allowlist parser for {@link MagicBarActionSpec.iconPath} — the geometry-only
|
|
8818
9506
|
* gate between a publisher-supplied glyph fragment and the DOM.
|
|
@@ -9034,6 +9722,15 @@ declare class FlyMagicActionsComponent {
|
|
|
9034
9722
|
* what stops `@for (…; track $index)` rebuilding the glyph each time.
|
|
9035
9723
|
*/
|
|
9036
9724
|
protected iconNodes(action: MagicBarActionView): readonly FlyMagicBarIconNode[];
|
|
9725
|
+
/**
|
|
9726
|
+
* Whether this action has a glyph to paint at all.
|
|
9727
|
+
*
|
|
9728
|
+
* Derived from the PARSED nodes, never from `iconPath` being a non-empty string: a fragment the
|
|
9729
|
+
* allowlist rejected parses to zero nodes, and treating that as "has an icon" would paint an
|
|
9730
|
+
* empty `<svg>` box — on a labelled action, a permanent gap in front of the text. The parse
|
|
9731
|
+
* memoizes, so asking twice costs nothing.
|
|
9732
|
+
*/
|
|
9733
|
+
protected hasGlyph(action: MagicBarActionView): boolean;
|
|
9037
9734
|
/** `null` (not `'default'`) so `[attr.data-tone]` omits the attribute entirely for the common case. */
|
|
9038
9735
|
protected toneAttr(action: MagicBarActionView): string | null;
|
|
9039
9736
|
/**
|
|
@@ -9164,6 +9861,17 @@ declare const FLY_MAGIC_BAR_ICONS: {
|
|
|
9164
9861
|
* the settings gear, not the mode switcher).
|
|
9165
9862
|
*/
|
|
9166
9863
|
readonly calendarView: "<rect x=\"3.5\" y=\"3.5\" width=\"17\" height=\"17\" rx=\"2.5\"/><path d=\"M3.5 12h17M12 3.5v17\"/>";
|
|
9864
|
+
/**
|
|
9865
|
+
* Gantt / outline "Indent" — the block pushed in, with the arrow pointing INTO the indent.
|
|
9866
|
+
* Pairs with {@link outdent}: the two differ only in the arrow, which is the convention every
|
|
9867
|
+
* word processor and desktop planner has shipped for decades and the reason both stay icon-only.
|
|
9868
|
+
*
|
|
9869
|
+
* Directional, so publishers pass `mirrorInRtl: true` alongside it — the block sits on the
|
|
9870
|
+
* reading-start side, which is the right edge in `ar`/`ur`.
|
|
9871
|
+
*/
|
|
9872
|
+
readonly indent: "<path d=\"M4 5h16M4 19h16\"/><path d=\"M11 9.7h9M11 14.3h9\"/><path d=\"M4.5 9.7 7.5 12l-3 2.3\"/>";
|
|
9873
|
+
/** Gantt / outline "Outdent" — {@link indent}'s block with the arrow pulling back out. */
|
|
9874
|
+
readonly outdent: "<path d=\"M4 5h16M4 19h16\"/><path d=\"M11 9.7h9M11 14.3h9\"/><path d=\"M7.5 9.7 4.5 12l3 2.3\"/>";
|
|
9167
9875
|
/** `UX/FlyOS Desktop-app/MainContent.dc.html:927` (`pubTabActions`'s local `P` table). */
|
|
9168
9876
|
readonly addEvidence: "<path d=\"M10.5 13.5a4 4 0 0 0 5.7 0l2-2a4 4 0 0 0-5.7-5.7l-.6.6\"/><path d=\"M13.5 10.5a4 4 0 0 0-5.7 0l-2 2a4 4 0 0 0 4.2 6.5\"/><path d=\"M17.5 15.5v5M15 18h5\"/>";
|
|
9169
9877
|
/** `MainContent.dc.html:928`. Reused for every "Edit …" action (evidence, link, task). */
|
|
@@ -9212,7 +9920,7 @@ type FlyMagicBarIconName = keyof typeof FLY_MAGIC_BAR_ICONS;
|
|
|
9212
9920
|
* App running standalone.
|
|
9213
9921
|
*
|
|
9214
9922
|
* ## The gap this closes
|
|
9215
|
-
* A view publishes one `MagicBarContribution` (skill: `magic-bar
|
|
9923
|
+
* A view publishes one `MagicBarContribution` (skill: `shell-magic-bar.md`)
|
|
9216
9924
|
* and, embedded in the desktop shell, the top-bar pill renders it. Standalone,
|
|
9217
9925
|
* nothing did — so every screen also kept a bespoke header-actions row
|
|
9218
9926
|
* (`[page-header-actions]` buttons) that duplicated the published actions in
|
|
@@ -10490,7 +11198,7 @@ type FlyCurrencySelectorValue = string | readonly string[] | null;
|
|
|
10490
11198
|
* `locked` is a different claim entirely: **the value is fixed on purpose**, because
|
|
10491
11199
|
* something downstream now depends on it (PPM freezes a project's currency the moment any
|
|
10492
11200
|
* financial row exists — changing it would silently re-denominate every stored amount).
|
|
10493
|
-
* A dimmed control with no explanation is exactly the failure `skills/magic-bar
|
|
11201
|
+
* A dimmed control with no explanation is exactly the failure `skills/shell-magic-bar.md`
|
|
10494
11202
|
* §3.6 names for actions ("a vanishing action teaches the user nothing"); the same argument
|
|
10495
11203
|
* applies to a frozen field. So `locked` renders differently on purpose: full-opacity (never
|
|
10496
11204
|
* dimmed — the value is not "unavailable", it is authoritative), no dropdown affordance at
|
|
@@ -10573,7 +11281,7 @@ declare class FlyCurrencySelectorComponent implements ControlValueAccessor {
|
|
|
10573
11281
|
*/
|
|
10574
11282
|
readonly locked: _angular_core.InputSignal<boolean>;
|
|
10575
11283
|
/**
|
|
10576
|
-
* i18n KEY (never resolved text — see `skills/magic-bar
|
|
11284
|
+
* i18n KEY (never resolved text — see `skills/shell-magic-bar.md` §3.4) explaining
|
|
10577
11285
|
* WHY the control is locked. Omit to use the localized `currency_selector.locked_default_reason`
|
|
10578
11286
|
* baseline key; supply your own only when that default reason is wrong for your case
|
|
10579
11287
|
* (mirrors `MagicBarActionSpec.disabledTipKey`'s "supply only when the default is wrong"
|
|
@@ -12902,6 +13610,13 @@ declare class FlyDataTableComponent {
|
|
|
12902
13610
|
/** `fly-state-message` key when `rows` is empty (omit to render nothing). */
|
|
12903
13611
|
readonly emptyKey: _angular_core.InputSignal<string | undefined>;
|
|
12904
13612
|
readonly emptyIconClass: _angular_core.InputSignal<string | undefined>;
|
|
13613
|
+
/**
|
|
13614
|
+
* The selected row's `id`, or `null`/omitted for no selection — the select-then-act model
|
|
13615
|
+
* (`skills/shell-ux-rulebook.md` §1) paints the matching `<tr>` with `--tint-sel` and
|
|
13616
|
+
* `aria-selected`. A page that still opens rows on activation (rather than selecting them) simply
|
|
13617
|
+
* never sets this; the table renders exactly as before.
|
|
13618
|
+
*/
|
|
13619
|
+
readonly selectedId: _angular_core.InputSignal<string | null>;
|
|
12905
13620
|
protected readonly skeletonRows: number[];
|
|
12906
13621
|
private readonly cellTemplates;
|
|
12907
13622
|
private readonly templateMap;
|
|
@@ -12913,13 +13628,14 @@ declare class FlyDataTableComponent {
|
|
|
12913
13628
|
*/
|
|
12914
13629
|
protected onRowActivate(event: Event, row: unknown): void;
|
|
12915
13630
|
protected cellValue(row: unknown, col: FlyColumn): unknown;
|
|
13631
|
+
protected isSelected(row: unknown): boolean;
|
|
12916
13632
|
/** Default text rendering — em-dash for absent values, verbatim otherwise. */
|
|
12917
13633
|
protected displayValue(row: unknown, col: FlyColumn): string;
|
|
12918
13634
|
protected headerAriaSort(col: FlyColumn): string | null;
|
|
12919
13635
|
protected sortDirFor(col: FlyColumn): string | null;
|
|
12920
13636
|
protected onHeaderClick(col: FlyColumn): void;
|
|
12921
13637
|
static ɵfac: _angular_core.ɵɵFactoryDeclaration<FlyDataTableComponent, never>;
|
|
12922
|
-
static ɵcmp: _angular_core.ɵɵComponentDeclaration<FlyDataTableComponent, "fly-data-table", never, { "columns": { "alias": "columns"; "required": true; "isSignal": true; }; "rows": { "alias": "rows"; "required": true; "isSignal": true; }; "loading": { "alias": "loading"; "required": false; "isSignal": true; }; "ariaLabelKey": { "alias": "ariaLabelKey"; "required": false; "isSignal": true; }; "sort": { "alias": "sort"; "required": false; "isSignal": true; }; "emptyKey": { "alias": "emptyKey"; "required": false; "isSignal": true; }; "emptyIconClass": { "alias": "emptyIconClass"; "required": false; "isSignal": true; }; }, { "sortChange": "sortChange"; "rowActivated": "rowActivated"; }, ["cellTemplates"], never, true, never>;
|
|
13638
|
+
static ɵcmp: _angular_core.ɵɵComponentDeclaration<FlyDataTableComponent, "fly-data-table", never, { "columns": { "alias": "columns"; "required": true; "isSignal": true; }; "rows": { "alias": "rows"; "required": true; "isSignal": true; }; "loading": { "alias": "loading"; "required": false; "isSignal": true; }; "ariaLabelKey": { "alias": "ariaLabelKey"; "required": false; "isSignal": true; }; "sort": { "alias": "sort"; "required": false; "isSignal": true; }; "emptyKey": { "alias": "emptyKey"; "required": false; "isSignal": true; }; "emptyIconClass": { "alias": "emptyIconClass"; "required": false; "isSignal": true; }; "selectedId": { "alias": "selectedId"; "required": false; "isSignal": true; }; }, { "sortChange": "sortChange"; "rowActivated": "rowActivated"; }, ["cellTemplates"], never, true, never>;
|
|
12923
13639
|
}
|
|
12924
13640
|
|
|
12925
13641
|
/**
|
|
@@ -14314,6 +15030,6 @@ declare const AUDIENCE_ERROR_CODES: {
|
|
|
14314
15030
|
};
|
|
14315
15031
|
type AudienceErrorCode = (typeof AUDIENCE_ERROR_CODES)[keyof typeof AUDIENCE_ERROR_CODES];
|
|
14316
15032
|
|
|
14317
|
-
export { AGENT_DRAG_MIME, AGENT_PAYLOAD_VERSION, APP_LOOKUP, AUDIENCE_ERROR_CODES, AUDIENCE_LIMITS, AUDIENCE_PRESETS, AUDIENCE_TERM_KINDS, AgentActionBus, AgentActionUnsupportedDispatchError, AgentCommandRegistry, AgentDropRegistry, AgentFlightAnimator, AgentLookupRegistry, AgentPayloadOversizeError, AudienceBuilderComponent, AuthService, BilingualFieldComponent, CRON_MODES, CRON_WEEKDAYS, ContextMenuComponent, DEFAULT_AGENT_PAYLOAD_LIMITS, DEFAULT_FLY_THEME_MODE, DS_BASELINE_LOCALES, DashboardKpiComponent, DialogResult, ENTITY_LINK_LAUNCHER, EntityLookupComponent, FLYOS_LAUNCH_EVENT, FLYOS_LAUNCH_REQUEST_EVENT, FLYOS_REMOTE_ROUTE_EVENT, FLY_ACCENT_PROPERTY, FLY_ADMIN_ROLES, FLY_CHUNK_RELOAD_FLAG, FLY_COMPACT_THRESHOLD, FLY_COUNTRIES, FLY_CURRENCIES_BRIEF_ENDPOINT, FLY_CURRENCY_DEFAULT_ENDPOINT, FLY_EMOJI_BY_ID, FLY_EMOJI_CATEGORIES, FLY_EMOJI_CATEGORY_BY_ID, FLY_EMOJI_DEFAULT_CATEGORIES, FLY_EMOJI_PACK, FLY_EMOJI_PACK_MISSING_MESSAGE, FLY_EMOJI_PREVIEW_COUNT, FLY_EMPTY_VALUE, FLY_LOCALE_CATALOG, FLY_MAGIC_BAR_EVENT, FLY_MAGIC_BAR_ICONS, FLY_MAGIC_BAR_STORE_KEY, FLY_NF_CACHE_HEAL_FLAG, FLY_RELOAD_DEBOUNCE_MS, FLY_RELOAD_REARM_MS, FLY_REMOTE_BASE_PATH, FLY_REMOTE_CONTEXT_EVENT, FLY_REMOTE_CONTEXT_STORE_KEY, FLY_REMOTE_OUTLET_DEPTH, FLY_REMOTE_ROUTES, FLY_SCAN_PENDING_DEFAULT_DELAY_MS, FLY_SCAN_PENDING_MAX_RETRIES, FLY_SCAN_PENDING_STATUS, FLY_SEARCH_DEBOUNCE_MS, FLY_SKIN_TONES, FLY_STANDALONE_AUTH_CONFIG, FLY_STRATEGY_OBJECTIVES_LOOKUP_ENDPOINT, FLY_THEME_MODE_IDS, FLY_VIEWPORT_IS_MOBILE, FLY_WINDOW_BREADCRUMBS_EVENT, FLY_WINDOW_BREADCRUMBS_STORE_KEY, FLY_WINDOW_HELP_HINT_EVENT, FLY_WINDOW_PAGE_TITLE_EVENT, FlyAchievementProgressComponent, FlyActionMenuComponent, FlyActionStackComponent, FlyAgentDraggableDirective, FlyAnimatedEmojiComponent, FlyAppHomeComponent, FlyAppTopbarComponent, FlyAppUnavailableComponent, FlyAuthLiveRefresh, FlyBadgeWallComponent, FlyBlockUiComponent, FlyBreadcrumbComponent, FlyButtonComponent, FlyBytesPipe, FlyCaptchaComponent, FlyCardActionsComponent, FlyCardBodyComponent, FlyCardComponent, FlyCardFooterComponent, FlyCardGridComponent, FlyCardMediaComponent, FlyCardMetaComponent, FlyCardStatusComponent, FlyCardTitleComponent, FlyCellDirective, FlyCheckboxComponent, FlyChipComponent, FlyChunkReloadErrorHandler, FlyClickOutsideDirective, FlyCollapsibleComponent, FlyCommentThreadComponent, FlyCompactNumberPipe, FlyConfirmDialogComponent, FlyControlDirective, FlyCronBuilderComponent, FlyCurrencyCatalogService, FlyCurrencySelectorComponent, FlyDataTableComponent, FlyDatePipe, FlyDateTimePipe, FlyDebouncer, FlyDecimalNumberPipe, FlyDeepLinkPrefetchService, FlyDetailCardComponent, FlyDetailShellComponent, FlyDrawerComponent, FlyDurationPipe, FlyDynamicFormComponent, FlyEmojiPickerComponent, FlyFieldComponent, FlyFileDownloadService, FlyFileUploadComponent, FlyFilterPanelComponent, FlyFormBannerComponent, FlyFormFooterComponent, FlyFormGridComponent, FlyFormSectionComponent, FlyFullNumberPipe, FlyGanttComponent, FlyHubClient, FlyIconButtonComponent, FlyIfAdminDirective, FlyIfRoleDirective, FlyImageUploadComponent, FlyLeaderboardComponent, FlyLifecyclePipelineComponent, FlyMagicActionsComponent, FlyMetaListComponent, FlyModalComponent, FlyModerationQueueComponent, FlyModuleIconDirective, FlyMoneyPipe, FlyOverviewKpiRowComponent, FlyOverviewRowsComponent, FlyOverviewSectionComponent, FlyOverviewSurfaceComponent, FlyPagerComponent, FlyPaginationComponent, FlyPeoplePickerComponent, FlyPointsTierComponent, FlyProgressComponent, FlyRelativeTimePipe, FlyRemoteContextService, FlyRemoteRouter, FlyRemoteRouterOutletComponent, FlySearchInputComponent, FlySectionHeaderComponent, FlySecureSrcDirective, FlySegmentedComponent, FlySelectComponent, FlySkeletonComponent, FlySliderComponent, FlySparklineComponent, FlySpinnerComponent, FlyStandaloneAuthCallbackComponent, FlyStandaloneAuthService, FlyStandaloneMagicActionsComponent, FlyStateMessageComponent, FlyStrategySelectorComponent, FlyDynamicFormComponent as FlySurveyFormComponent, FlyTabComponent, FlyTabsComponent, FlyTagsInputComponent, FlyThemeService, FlyTimePipe, FlyToastService, FlyToggleComponent, FlyTooltipDirective, FlyTreeNavComponent, FlyTypeaheadComponent, FlyUserDirectoryService, FlyWindowHelpService, FlyWindowTitleService, FlyosPendingLaunchesGlobalKey, FlyosShellHandlesLaunchRequestsGlobalKey, FlyosShellOwnsHistoryGlobalKey, GANTT_DEPENDENCY_TYPES, GANTT_ROW_TINT_ALPHA, GANTT_ZOOMS, I18nService, LAUNCH_CONTEXT, MAGIC_BAR_SEARCH_WIDTH_DEFAULT, MAGIC_BAR_SEARCH_WIDTH_MAX, MAGIC_BAR_SEARCH_WIDTH_MIN, MagicBarRegistry, MessageBoxButtons, MessageBoxComponent, MessageBoxIcon, MessageBoxService, MockAuthService, NOVA_PRIORITY_TONE, NOVA_STATUS_TONE, NOVA_TONE_FALLBACK, OverlayStack, PRESENCE_COLORS, PageHeaderComponent, RTL_LOCALE_SET, SHARE_ORG_CHART_SYSTEM_KEY_APPS, SHARE_ORG_CHART_SYSTEM_KEY_DEFAULT, SHARE_PANEL_DEFAULT_FILE_LEVELS, STATE_DEFAULT_ICONS, STATE_DEFAULT_MESSAGE_KEYS, STEP_UP_CODE, STEP_UP_REAUTH_HANDLER, STEP_UP_RETURN_KEY, SUPPORTED_AGENT_PAYLOAD_VERSIONS, SharePanelComponent, SourceAppResolver, StandaloneWindowManagerService, StatusBadgeComponent, StepUpService, ToastHostComponent, TranslatePipe, WINDOW_DATA, WINDOW_HELP_HINT, WindowBreadcrumbsRegistry, WindowManagerService, applySkinTone, applySuggestion, ariaSort, buildCron, canConfirm, canGoNext$1 as canGoNext, canGoPrev$1 as canGoPrev, captureFocus, clampMagicBarSearchWidth, clampPage$1 as clampPage, clampSliderValue, connectRemoteLaunch, deepestFlyMatch, enterActivatesNatively, filterGroup, filterSuggestions, findLocaleByDialect, findLocaleByPrefix, firstEnabledIndex, firstModuleIndex, flattenModules, flyAdminGuard, flyApiErrorMessage, flyCaptchaBase64Utf8, flyCaptchaBuildToken, flyCaptchaSha256Hex, flyCompactNumber, flyDebounced, flyDecimalNumber, flyDownloadBlob, flyDuration, flyEmojiFor, flyEmojiIsTonable, flyEmojiPackUrl, flyExportFileName, flyFirstEnabledIndex, flyFormatBytes, flyFormatDate, flyFormatDateTime, flyFormatMoney, flyFormatTime, flyFullNumber, flyNextEnabledIndex, flyNextSegmentIndex, flyRelativeTime, flyResolveActiveTab, flyRoleGuard, flyScanPendingDelayMs, flyScanRetry, flySignedCompact, flySkinToneLabelKey, flyStandaloneAuthGuard, flyStandaloneAuthInterceptor, flyToDateOnly, flyToPage, flyUnwrap, flyUnwrapCurrencies, flyUnwrapCurrency, flyUnwrapLenient, flyUnwrapObjectiveLookup, hasAnyRoleIn, healNativeFederationCacheOnce, initialExpanded, isAccentColor, isChunkLoadError, isFlyAuthStorePopulated, isNativeFederationCacheError, isRtlLocale, isRtlLocaleEntry, isValidCron, isValidSingleField, loadRemoteStyles, magicBarOwnerKey, magicBarSearchText, matchFlyRoutePattern, matchFlyRoutePrefix, matchFlyRouteTable, nextEnabledIndex, nextModuleIndex, nextSegmentIndex, nextSort, normalizeFlyTheme, normalizeRoles, novaPriorityToneVar, novaStatusToneVar, overlayStack, canGoNext as pagerCanGoNext, canGoPrev as pagerCanGoPrev, clampPage as pagerClampPage, parseCron, parseStepUpChallenge, parseTags, prefetchRemoteStyles, presenceColorFor, printConsoleSecurityWarning, provideFlyChunkReloadRecovery, provideFlyEmojiPack, provideFlyOfflineAuth, provideFlyStandaloneAuth, reloadOnceForChunkError, requestAppLaunch, resolveActiveModule, resolveActiveSection, resolveActiveTab, resolveCellValue, resolveStateIcon, resolveStateMessageKey, restoreFocus, sameTags, sectionHintKey, sectionLayout, sliderTrackGradient, sparklinePath, sparklinePoints, stepUpInterceptor, stepUpReturnKey, trimAgentPayload, trimAgentString, unloadRemoteStyles, utf8ByteLength, validateAgentPayload, warnIfEmbeddedSessionMissing };
|
|
14318
|
-
export type { ActionMenuItem, AgentAction, AgentActionDispatch, AgentActionVerb, AgentChipHostInputs, AgentCommand, AgentCommandContextBinding, AgentCommandHandle, AgentCommandRegistration, AgentCommandScope, AgentCommandSlashSpec, AgentDragPayload, AgentDraggableItem, AgentDropChipMode, AgentDropRendererRegistration, AgentEnvelopeAttachment, AgentMcpScope, AgentMessageEnvelope, AgentPayloadLimits, AgentPayloadValidationResult, AppEveryonePrincipal, AppEveryoneTerm, AppLookup, AppLookupEntry, AudienceEditTarget, AudienceErrorCode, AudienceFilter, AudienceOptions, AudiencePresetKind, AudienceTerm, AudienceTermKind, BreadcrumbItem, ButtonSize, ButtonVariant, CardDensity, CardLayout, ChartTerm, ChildWindowData, ChipTone, ConfirmKind, ConnectRemoteLaunchOptions, ContextMenuAlign, ContextMenuItem, ContextMenuSection, CronAdvancedFieldDef, CronMode, CronParts, CronWeekday, DesktopApp, DesktopAppCategory, DesktopAppKind, DetailSection, DialogResultWithAcknowledgement, EmbeddedSessionProbe, EntityLinkLauncher, EntityLinkSelection, FilterGroup, FlyAchievementRow, FlyApiError, FlyApiResponse, FlyAppHomeLayout, FlyAppModule, FlyAppModuleSection, FlyAppUnavailableState, FlyAuthRefreshPayload, FlyAuthStoreReadable, FlyBadgeTile, FlyBreadcrumbItem, FlyCaptchaChallenge, FlyCaptchaSolution, FlyCaptchaState, FlyCellContext, FlyColumn, FlyColumnKind, FlyComment, FlyCommentDeleteRequest, FlyCommentEditRequest, FlyCommentLoadMoreRequest, FlyCommentLoadRepliesRequest, FlyCommentLockToggleRequest, FlyCommentPage, FlyCommentReportReason, FlyCommentReportRequest, FlyCommentReportStatus, FlyCommentSubmitRequest, FlyCountry, FlyCurrency, FlyCurrencyFetchFn, FlyCurrencySelectorMode, FlyCurrencySelectorValue, FlyDeepLinkPrefetchRoute, FlyDrawerBodyPadding, FlyDrawerPosition, FlyDrawerSide, FlyDrawerSize, FlyDrawerVariant, FlyEmojiCategory, FlyEmojiCell, FlyEmojiEntry, FlyEmojiPack, FlyEmojiPackEntry, FlyEmojiPackManifest, FlyEmojiPickerSize, FlyEmojiPickerTab, FlyEmojiSection, FlyFileInfo, FlyFileSelection, FlyFormAnswer, FlyFormAnswerValue, FlyFormDefinition, FlyFormFieldOptions, FlyFormOption, FlyFormQuestion, FlyFormQuestionType, FlyFormScoreDisplay, FlyFormatMoneyOptions, FlyLaunchEventDetail, FlyLaunchRequestDetail, FlyLeaderboardRow, FlyLiveRefreshOptions, FlyLocaleEntry, FlyMagicBarIconName, FlyMetaItem, FlyModerationLoadPageRequest, FlyModerationLockThreadRequest, FlyModerationOpenSubjectRequest, FlyModerationReport, FlyModerationReportPage, FlyModerationResolutionStatus, FlyModerationResolveRequest, FlyMoneyDisplay, FlyNavigableItem, FlyOfflineAuthConfig, FlyPageMeta, FlyPageResult, FlyPaged, FlyPeoplePickerMode, FlyPeoplePickerOption, FlyPeopleSearchFn, FlyPointsSummary, FlyRemoteContext, FlyRemoteEagerRoute, FlyRemoteLazyRoute, FlyRemoteLoadedComponent, FlyRemoteMatch, FlyRemoteRoute, FlyRemoteRouteEventDetail, FlySearchExpandTrigger, FlySearchInputSize, FlySecureSrcState, FlySelectOption, FlySelectValue, FlySkeletonAnimation, FlySkeletonLayout, FlySkeletonShape, FlySkinTone, FlySort, FlyStandaloneAuthConfig, FlyStrategyObjectiveRef, FlyStrategyObjectiveSearchFn, FlyFileSelection as FlySurveyFileSelection, FlyFormAnswer as FlySurveyFormAnswer, FlyFormAnswerValue as FlySurveyFormAnswerValue, FlyFormDefinition as FlySurveyFormDefinition, FlyFormFieldOptions as FlySurveyFormFieldOptions, FlyFormOption as FlySurveyFormOption, FlyFormQuestion as FlySurveyFormQuestion, FlyFormQuestionType as FlySurveyQuestionType, FlyTenantDefaultCurrencyFetchFn, FlyThemeMode, FlyTooltipPlacement, FlyTreeNavNode, FlyTypeaheadOption, FlyWindowHelpHintEventDetail, FlyWindowHelpPublisher, FlyWindowPageTitleEventDetail, FlyWindowTitlePublisher, FlyosPendingLaunches, FocusRestore, FormBannerKind, GanttDependency, GanttDependencyCreate, GanttDependencyDelete, GanttDependencyType, GanttRow, GanttRowDatesChange, GanttRowKind, GanttZoom, IconButtonVariant, LaunchContext, LifecycleRollupItem, LifecycleStep, LoadBundleOptions, LoadRemoteStylesOptions, LookupDescriptor, LookupHandle, LookupRegistration, LookupResult, LookupSearch, MagicBarAction, MagicBarActionKind, MagicBarActionSpec, MagicBarActionView, MagicBarContribution, MagicBarGroup, MagicBarGroupSpec, MagicBarGroupView, MagicBarOwnerRef, MagicBarPublisher, MagicBarRadioMenu, MagicBarRadioMenuSpec, MagicBarRadioMenuView, MagicBarRadioOption, MagicBarSearch, MagicBarSearchSeed, MagicBarSearchSpec, MagicBarSearchView, MagicBarTextParams, MagicBarTone, MagicBarView, MessageBoxButton, MessageBoxDontAskAgainConfig, MessageBoxOptions, MessageBoxOptionsWithAcknowledgement, MockAuthConfig, OpenWindowOptions, OuPrincipal, OuTerm, OverlayHandle, OverviewKpiItem, OverviewKpiTone, OverviewRow, PageHeaderVariant, PresetTerm, ProgressTone, RemoteAppDef, RequestAppLaunchOptions, RoleOuLookupRow, RolePrincipal, RolesTerm, SegmentedOption, SegmentedVariant, ShareOrgChartOption, ShareOuNode, SharePanelLevelOption, SharePermissionEntry, SharePrincipal, SharePrincipalKind, ShareUserResult, StateMessageKind, StepUpChallenge, StepUpReauthHandler, StepUpReauthRequest, TabsVariant, ToastAction, ToastEntry, ToastOptions, ToastVariant, User, UserPrincipal, UsersTerm, WindowBreadcrumb, WindowHelpHint, WindowInstance, WindowState };
|
|
15033
|
+
export { AGENT_DRAG_MIME, AGENT_PAYLOAD_VERSION, APP_LOOKUP, AUDIENCE_ERROR_CODES, AUDIENCE_LIMITS, AUDIENCE_PRESETS, AUDIENCE_TERM_KINDS, AgentActionBus, AgentActionUnsupportedDispatchError, AgentCommandRegistry, AgentDropRegistry, AgentFlightAnimator, AgentLookupRegistry, AgentPayloadOversizeError, AudienceBuilderComponent, AuthService, BilingualFieldComponent, CRON_MODES, CRON_WEEKDAYS, ContextMenuComponent, DEFAULT_AGENT_PAYLOAD_LIMITS, DEFAULT_FLY_THEME_MODE, DS_BASELINE_LOCALES, DashboardKpiComponent, DialogResult, ENTITY_LINK_LAUNCHER, EntityLookupComponent, FLYOS_LAUNCH_EVENT, FLYOS_LAUNCH_REQUEST_EVENT, FLYOS_REMOTE_ROUTE_EVENT, FLY_ACCENT_PROPERTY, FLY_ADMIN_ROLES, FLY_CHUNK_RELOAD_FLAG, FLY_COMPACT_THRESHOLD, FLY_COUNTRIES, FLY_CURRENCIES_BRIEF_ENDPOINT, FLY_CURRENCY_DEFAULT_ENDPOINT, FLY_EMOJI_BY_ID, FLY_EMOJI_CATEGORIES, FLY_EMOJI_CATEGORY_BY_ID, FLY_EMOJI_DEFAULT_CATEGORIES, FLY_EMOJI_PACK, FLY_EMOJI_PACK_MISSING_MESSAGE, FLY_EMOJI_PREVIEW_COUNT, FLY_EMPTY_VALUE, FLY_GANTT_DEFAULTS, FLY_LAUNCH_CONTEXT_EVENT, FLY_LAUNCH_CONTEXT_STORE_KEY, FLY_LOCALE_CATALOG, FLY_MAGIC_BAR_EVENT, FLY_MAGIC_BAR_ICONS, FLY_MAGIC_BAR_STORE_KEY, FLY_NF_CACHE_HEAL_FLAG, FLY_RELOAD_DEBOUNCE_MS, FLY_RELOAD_REARM_MS, FLY_REMOTE_BASE_PATH, FLY_REMOTE_CONTEXT_EVENT, FLY_REMOTE_CONTEXT_STORE_KEY, FLY_REMOTE_OUTLET_DEPTH, FLY_REMOTE_ROUTES, FLY_SCAN_PENDING_DEFAULT_DELAY_MS, FLY_SCAN_PENDING_MAX_RETRIES, FLY_SCAN_PENDING_STATUS, FLY_SEARCH_DEBOUNCE_MS, FLY_SKIN_TONES, FLY_STANDALONE_AUTH_CONFIG, FLY_STRATEGY_OBJECTIVES_LOOKUP_ENDPOINT, FLY_THEME_MODE_IDS, FLY_VIEWPORT_IS_MOBILE, FLY_WINDOW_BREADCRUMBS_EVENT, FLY_WINDOW_BREADCRUMBS_STORE_KEY, FLY_WINDOW_HELP_HINT_EVENT, FLY_WINDOW_PAGE_TITLE_EVENT, FlyAchievementProgressComponent, FlyActionMenuComponent, FlyActionStackComponent, FlyAgentDraggableDirective, FlyAnimatedEmojiComponent, FlyAppHomeComponent, FlyAppTopbarComponent, FlyAppUnavailableComponent, FlyAuthLiveRefresh, FlyBadgeWallComponent, FlyBlockUiComponent, FlyBreadcrumbComponent, FlyButtonComponent, FlyBytesPipe, FlyCaptchaComponent, FlyCardActionsComponent, FlyCardBodyComponent, FlyCardComponent, FlyCardFooterComponent, FlyCardGridComponent, FlyCardMediaComponent, FlyCardMetaComponent, FlyCardStatusComponent, FlyCardTitleComponent, FlyCellDirective, FlyCheckboxComponent, FlyChipComponent, FlyChunkReloadErrorHandler, FlyClickOutsideDirective, FlyCollapsibleComponent, FlyCommentThreadComponent, FlyCompactNumberPipe, FlyConfirmDialogComponent, FlyControlDirective, FlyCronBuilderComponent, FlyCurrencyCatalogService, FlyCurrencySelectorComponent, FlyDataTableComponent, FlyDatePipe, FlyDateTimePipe, FlyDebouncer, FlyDecimalNumberPipe, FlyDeepLinkPrefetchService, FlyDetailCardComponent, FlyDetailShellComponent, FlyDrawerComponent, FlyDurationPipe, FlyDynamicFormComponent, FlyEmojiPickerComponent, FlyFieldComponent, FlyFileDownloadService, FlyFileUploadComponent, FlyFilterPanelComponent, FlyFormBannerComponent, FlyFormFooterComponent, FlyFormGridComponent, FlyFormSectionComponent, FlyFullNumberPipe, FlyGanttComponent, FlyHubClient, FlyIconButtonComponent, FlyIfAdminDirective, FlyIfRoleDirective, FlyImageUploadComponent, FlyLaunchContextService, FlyLeaderboardComponent, FlyLifecyclePipelineComponent, FlyMagicActionsComponent, FlyMetaListComponent, FlyModalComponent, FlyModerationQueueComponent, FlyModuleIconDirective, FlyMoneyPipe, FlyOverviewKpiRowComponent, FlyOverviewRowsComponent, FlyOverviewSectionComponent, FlyOverviewSurfaceComponent, FlyPagerComponent, FlyPaginationComponent, FlyPeoplePickerComponent, FlyPointsTierComponent, FlyProgressComponent, FlyRelativeTimePipe, FlyRemoteContextService, FlyRemoteRouter, FlyRemoteRouterOutletComponent, FlySearchInputComponent, FlySectionHeaderComponent, FlySecureSrcDirective, FlySegmentedComponent, FlySelectComponent, FlySkeletonComponent, FlySliderComponent, FlySparklineComponent, FlySpinnerComponent, FlyStandaloneAuthCallbackComponent, FlyStandaloneAuthService, FlyStandaloneMagicActionsComponent, FlyStateMessageComponent, FlyStrategySelectorComponent, FlyDynamicFormComponent as FlySurveyFormComponent, FlyTabComponent, FlyTabsComponent, FlyTagsInputComponent, FlyThemeService, FlyTimePipe, FlyToastService, FlyToggleComponent, FlyTooltipDirective, FlyTreeNavComponent, FlyTypeaheadComponent, FlyUserDirectoryService, FlyWindowHelpService, FlyWindowTitleService, FlyosPendingLaunchesGlobalKey, FlyosShellHandlesLaunchRequestsGlobalKey, FlyosShellOwnsHistoryGlobalKey, GANTT_DEPENDENCY_TYPES, GANTT_LABEL_W_DEFAULT, GANTT_LABEL_W_MAX, GANTT_LABEL_W_MIN, GANTT_ROW_TINT_ALPHA, GANTT_ZOOMS, I18nService, LAUNCH_CONTEXT, MAGIC_BAR_SEARCH_WIDTH_DEFAULT, MAGIC_BAR_SEARCH_WIDTH_MAX, MAGIC_BAR_SEARCH_WIDTH_MIN, MagicBarRegistry, MessageBoxButtons, MessageBoxComponent, MessageBoxIcon, MessageBoxService, MockAuthService, NOVA_PRIORITY_TONE, NOVA_STATUS_TONE, NOVA_TONE_FALLBACK, OverlayStack, PRESENCE_COLORS, PageHeaderComponent, RTL_LOCALE_SET, SHARE_ORG_CHART_SYSTEM_KEY_APPS, SHARE_ORG_CHART_SYSTEM_KEY_DEFAULT, SHARE_PANEL_DEFAULT_FILE_LEVELS, STATE_DEFAULT_ICONS, STATE_DEFAULT_MESSAGE_KEYS, STEP_UP_CODE, STEP_UP_REAUTH_HANDLER, STEP_UP_RETURN_KEY, SUPPORTED_AGENT_PAYLOAD_VERSIONS, SharePanelComponent, SourceAppResolver, StandaloneWindowManagerService, StatusBadgeComponent, StepUpService, ToastHostComponent, TranslatePipe, WINDOW_DATA, WINDOW_HELP_HINT, WindowBreadcrumbsRegistry, WindowManagerService, applyGanttRowReorder, applySkinTone, applySuggestion, ariaSort, buildCron, canConfirm, canGoNext$1 as canGoNext, canGoPrev$1 as canGoPrev, captureFocus, clampMagicBarSearchWidth, clampPage$1 as clampPage, clampSliderValue, connectRemoteLaunch, deepestFlyMatch, enterActivatesNatively, filterGanttRows, filterGroup, filterSuggestions, findLocaleByDialect, findLocaleByPrefix, firstEnabledIndex, firstModuleIndex, flattenModules, flyAdminGuard, flyApiErrorMessage, flyCaptchaBase64Utf8, flyCaptchaBuildToken, flyCaptchaSha256Hex, flyCompactNumber, flyDebounced, flyDecimalNumber, flyDownloadBlob, flyDuration, flyEmojiFor, flyEmojiIsTonable, flyEmojiPackUrl, flyExportFileName, flyFirstEnabledIndex, flyFormatBytes, flyFormatDate, flyFormatDateTime, flyFormatMoney, flyFormatTime, flyFullNumber, flyNextEnabledIndex, flyNextSegmentIndex, flyRelativeTime, flyResolveActiveTab, flyRoleGuard, flyScanPendingDelayMs, flyScanRetry, flySignedCompact, flySkinToneLabelKey, flyStandaloneAuthGuard, flyStandaloneAuthInterceptor, flyToDateOnly, flyToPage, flyUnwrap, flyUnwrapCurrencies, flyUnwrapCurrency, flyUnwrapLenient, flyUnwrapObjectiveLookup, ganttOutlineBarItems, ganttPeriodBarItem, hasAnyRoleIn, healNativeFederationCacheOnce, initialExpanded, isAccentColor, isChunkLoadError, isFlyAuthStorePopulated, isNativeFederationCacheError, isRtlLocale, isRtlLocaleEntry, isValidCron, isValidSingleField, linkAnchorsFor, loadRemoteStyles, magicBarOwnerKey, magicBarSearchText, matchFlyRoutePattern, matchFlyRoutePrefix, matchFlyRouteTable, nextEnabledIndex, nextModuleIndex, nextSegmentIndex, nextSort, normalizeFlyTheme, normalizeGanttSearchText, normalizeRoles, novaPriorityToneVar, novaStatusToneVar, orderMagicBarItems, overlayStack, canGoNext as pagerCanGoNext, canGoPrev as pagerCanGoPrev, clampPage as pagerClampPage, parseCron, parseStepUpChallenge, parseTags, prefetchRemoteStyles, presenceColorFor, printConsoleSecurityWarning, provideFlyChunkReloadRecovery, provideFlyEmojiPack, provideFlyGanttDefaults, provideFlyOfflineAuth, provideFlyStandaloneAuth, reloadOnceForChunkError, requestAppLaunch, resolveActiveModule, resolveActiveSection, resolveActiveTab, resolveCellValue, resolveStateIcon, resolveStateMessageKey, restoreFocus, sameTags, sectionHintKey, sectionLayout, sliderTrackGradient, sparklinePath, sparklinePoints, stepUpInterceptor, stepUpReturnKey, trimAgentPayload, trimAgentString, unloadRemoteStyles, utf8ByteLength, validateAgentPayload, warnIfEmbeddedSessionMissing };
|
|
15034
|
+
export type { ActionMenuItem, AgentAction, AgentActionDispatch, AgentActionVerb, AgentChipHostInputs, AgentCommand, AgentCommandContextBinding, AgentCommandHandle, AgentCommandRegistration, AgentCommandScope, AgentCommandSlashSpec, AgentDragPayload, AgentDraggableItem, AgentDropChipMode, AgentDropRendererRegistration, AgentEnvelopeAttachment, AgentMcpScope, AgentMessageEnvelope, AgentPayloadLimits, AgentPayloadValidationResult, AppEveryonePrincipal, AppEveryoneTerm, AppLookup, AppLookupEntry, AudienceEditTarget, AudienceErrorCode, AudienceFilter, AudienceOptions, AudiencePresetKind, AudienceTerm, AudienceTermKind, BreadcrumbItem, ButtonSize, ButtonVariant, CardDensity, CardLayout, ChartTerm, ChildWindowData, ChipTone, ConfirmKind, ConnectRemoteLaunchOptions, ContextMenuAlign, ContextMenuItem, ContextMenuSection, CronAdvancedFieldDef, CronMode, CronParts, CronWeekday, DesktopApp, DesktopAppCategory, DesktopAppKind, DetailSection, DialogResultWithAcknowledgement, EmbeddedSessionProbe, EntityLinkLauncher, EntityLinkSelection, FilterGroup, FlyAchievementRow, FlyApiError, FlyApiResponse, FlyAppHomeLayout, FlyAppModule, FlyAppModuleSection, FlyAppUnavailableState, FlyAuthRefreshPayload, FlyAuthStoreReadable, FlyBadgeTile, FlyBreadcrumbItem, FlyCaptchaChallenge, FlyCaptchaSolution, FlyCaptchaState, FlyCellContext, FlyColumn, FlyColumnKind, FlyComment, FlyCommentDeleteRequest, FlyCommentEditRequest, FlyCommentLoadMoreRequest, FlyCommentLoadRepliesRequest, FlyCommentLockToggleRequest, FlyCommentPage, FlyCommentReportReason, FlyCommentReportRequest, FlyCommentReportStatus, FlyCommentSubmitRequest, FlyCountry, FlyCurrency, FlyCurrencyFetchFn, FlyCurrencySelectorMode, FlyCurrencySelectorValue, FlyDeepLinkPrefetchRoute, FlyDrawerBodyPadding, FlyDrawerPosition, FlyDrawerSide, FlyDrawerSize, FlyDrawerVariant, FlyEmojiCategory, FlyEmojiCell, FlyEmojiEntry, FlyEmojiPack, FlyEmojiPackEntry, FlyEmojiPackManifest, FlyEmojiPickerSize, FlyEmojiPickerTab, FlyEmojiSection, FlyFileInfo, FlyFileSelection, FlyFormAnswer, FlyFormAnswerValue, FlyFormDefinition, FlyFormFieldOptions, FlyFormOption, FlyFormQuestion, FlyFormQuestionType, FlyFormScoreDisplay, FlyFormatMoneyOptions, FlyGanttDefaults, FlyLaunchEventDetail, FlyLaunchRequestDetail, FlyLeaderboardRow, FlyLiveRefreshOptions, FlyLocaleEntry, FlyMagicBarIconName, FlyMetaItem, FlyModerationLoadPageRequest, FlyModerationLockThreadRequest, FlyModerationOpenSubjectRequest, FlyModerationReport, FlyModerationReportPage, FlyModerationResolutionStatus, FlyModerationResolveRequest, FlyMoneyDisplay, FlyNavigableItem, FlyOfflineAuthConfig, FlyPageMeta, FlyPageResult, FlyPaged, FlyPeoplePickerMode, FlyPeoplePickerOption, FlyPeopleSearchFn, FlyPointsSummary, FlyRemoteContext, FlyRemoteEagerRoute, FlyRemoteLazyRoute, FlyRemoteLoadedComponent, FlyRemoteMatch, FlyRemoteRoute, FlyRemoteRouteEventDetail, FlySearchExpandTrigger, FlySearchInputSize, FlySecureSrcState, FlySelectOption, FlySelectValue, FlySkeletonAnimation, FlySkeletonLayout, FlySkeletonShape, FlySkinTone, FlySort, FlyStandaloneAuthConfig, FlyStrategyObjectiveRef, FlyStrategyObjectiveSearchFn, FlyFileSelection as FlySurveyFileSelection, FlyFormAnswer as FlySurveyFormAnswer, FlyFormAnswerValue as FlySurveyFormAnswerValue, FlyFormDefinition as FlySurveyFormDefinition, FlyFormFieldOptions as FlySurveyFormFieldOptions, FlyFormOption as FlySurveyFormOption, FlyFormQuestion as FlySurveyFormQuestion, FlyFormQuestionType as FlySurveyQuestionType, FlyTenantDefaultCurrencyFetchFn, FlyThemeMode, FlyTooltipPlacement, FlyTreeNavNode, FlyTypeaheadOption, FlyWindowHelpHintEventDetail, FlyWindowHelpPublisher, FlyWindowPageTitleEventDetail, FlyWindowTitlePublisher, FlyosPendingLaunches, FocusRestore, FormBannerKind, GanttDependency, GanttDependencyCreate, GanttDependencyDelete, GanttDependencyType, GanttLinkVm, GanttRow, GanttRowDatesChange, GanttRowIndentChange, GanttRowKind, GanttRowReorder, GanttZoom, IconButtonVariant, LaunchContext, LifecycleRollupItem, LifecycleStep, LoadBundleOptions, LoadRemoteStylesOptions, LookupDescriptor, LookupHandle, LookupRegistration, LookupResult, LookupSearch, MagicBarAction, MagicBarActionKind, MagicBarActionSpec, MagicBarActionView, MagicBarContribution, MagicBarGroup, MagicBarGroupSpec, MagicBarGroupView, MagicBarOwnerRef, MagicBarPublisher, MagicBarRadioMenu, MagicBarRadioMenuSpec, MagicBarRadioMenuView, MagicBarRadioOption, MagicBarSearch, MagicBarSearchSeed, MagicBarSearchSpec, MagicBarSearchView, MagicBarTextParams, MagicBarTone, MagicBarView, MessageBoxButton, MessageBoxDontAskAgainConfig, MessageBoxOptions, MessageBoxOptionsWithAcknowledgement, MockAuthConfig, OpenWindowOptions, OuPrincipal, OuTerm, OverlayHandle, OverviewKpiItem, OverviewKpiTone, OverviewRow, PageHeaderVariant, PresetTerm, ProgressTone, RemoteAppDef, RequestAppLaunchOptions, RoleOuLookupRow, RolePrincipal, RolesTerm, SegmentedOption, SegmentedVariant, ShareOrgChartOption, ShareOuNode, SharePanelLevelOption, SharePermissionEntry, SharePrincipal, SharePrincipalKind, ShareUserResult, StateMessageKind, StepUpChallenge, StepUpReauthHandler, StepUpReauthRequest, TabsVariant, ToastAction, ToastEntry, ToastOptions, ToastVariant, User, UserPrincipal, UsersTerm, WindowBreadcrumb, WindowHelpHint, WindowInstance, WindowState };
|
|
14319
15035
|
//# sourceMappingURL=flyos-design-system.d.ts.map
|