@truenas/ui-components 0.7.8 → 0.7.10

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@truenas/ui-components",
3
- "version": "0.7.8",
3
+ "version": "0.7.10",
4
4
  "publishConfig": {
5
5
  "registry": "https://registry.npmjs.org",
6
6
  "access": "public"
@@ -8829,6 +8829,14 @@ declare class TnListComponent {
8829
8829
  * The primary-text slot is the deliberate exception — it has no gate, so
8830
8830
  * `[tnListItemTitle]` and `[tnListItemPrimary]` render either way. See the
8831
8831
  * comment in `list-item.component.html` for why the asymmetry is there.
8832
+ *
8833
+ * `[testId]` names the row for automation. It lands on the host, which is both
8834
+ * the click target (`(click)` is a host binding) and the `listitem` — so one id
8835
+ * addresses the row whether a suite clicks it or reads what it renders. The
8836
+ * value is written verbatim, with no element-type prefix, matching the other
8837
+ * components whose host *is* the target (`tn-tree-node`, `tn-table`): a row of
8838
+ * a list is not a control whose type the library can name, and its meaning
8839
+ * comes from the list it sits in, which only the consumer knows.
8832
8840
  */
8833
8841
  declare class TnListItemComponent {
8834
8842
  disabled: _angular_core.InputSignal<boolean>;
@@ -8853,7 +8861,7 @@ declare class TnListItemComponent {
8853
8861
  hasThirdText: _angular_core.Signal<boolean>;
8854
8862
  onClick(event: Event): void;
8855
8863
  static ɵfac: _angular_core.ɵɵFactoryDeclaration<TnListItemComponent, never>;
8856
- static ɵcmp: _angular_core.ɵɵComponentDeclaration<TnListItemComponent, "tn-list-item", never, { "disabled": { "alias": "disabled"; "required": false; "isSignal": true; }; "clickable": { "alias": "clickable"; "required": false; "isSignal": true; }; "dense": { "alias": "dense"; "required": false; "isSignal": true; }; "wrap": { "alias": "wrap"; "required": false; "isSignal": true; }; }, { "itemClick": "itemClick"; }, ["leadingIcons", "leadingAvatars", "secondaryLines", "secondaryTexts", "trailing"], ["[tnListIcon], [tnListAvatar]", "[tnListItemTitle], [tnListItemPrimary]", "*", "[tnListItemLine], [tnListItemSecondary]", "[tnListItemTrailing]"], true, never>;
8864
+ static ɵcmp: _angular_core.ɵɵComponentDeclaration<TnListItemComponent, "tn-list-item", never, { "disabled": { "alias": "disabled"; "required": false; "isSignal": true; }; "clickable": { "alias": "clickable"; "required": false; "isSignal": true; }; "dense": { "alias": "dense"; "required": false; "isSignal": true; }; "wrap": { "alias": "wrap"; "required": false; "isSignal": true; }; }, { "itemClick": "itemClick"; }, ["leadingIcons", "leadingAvatars", "secondaryLines", "secondaryTexts", "trailing"], ["[tnListIcon], [tnListAvatar]", "[tnListItemTitle], [tnListItemPrimary]", "*", "[tnListItemLine], [tnListItemSecondary]", "[tnListItemTrailing]"], true, [{ directive: typeof TnTestIdDirective; inputs: { "tnTestId": "testId"; }; outputs: {}; }]>;
8857
8865
  }
8858
8866
 
8859
8867
  /**
@@ -14823,15 +14831,89 @@ declare class TnSidePanelHeaderActionDirective {
14823
14831
  * own, focus it yourself once the panel is open; the component leaves focus
14824
14832
  * alone as soon as it is inside the panel. `lib/a11y/initial-focus.ts` holds
14825
14833
  * the reasoning for capturing the container rather than a control.
14834
+ *
14835
+ * WHERE IT RENDERS, AND WHY THAT DECIDES WHAT IT STACKS AGAINST
14836
+ * ------------------------------------------------------------
14837
+ * The panel renders through a CDK `OverlayRef` created WHEN IT OPENS (#322),
14838
+ * which is what makes it stack with `TnDialog`, `tn-menu` and tooltips by open
14839
+ * order: whatever attached last paints on top, in both directions. It used to
14840
+ * append its overlay to `<body>` at construction time with a fixed `z-index`,
14841
+ * and the CDK overlay container is a `<body>` child with the same one — so the
14842
+ * winner was whichever element `<body>` happened to receive last, which follows
14843
+ * nothing a caller can see. A panel opened FROM a dialog landed under that
14844
+ * dialog's backdrop; on a browser with the popover API, where CDK puts its
14845
+ * overlays in the top layer, no `z-index` on a `<body>` child could have won at
14846
+ * all.
14847
+ *
14848
+ * Three things follow from being a CDK overlay, and each replaces something
14849
+ * this component used to do for itself:
14850
+ *
14851
+ * - **Escape reaches the topmost overlay only**, through CDK's
14852
+ * `OverlayKeyboardDispatcher`, rather than through a `keydown` handler on the
14853
+ * panel that stopped propagation to keep a dialog underneath from closing too.
14854
+ * The panel therefore also closes on Escape pressed outside it, which is what
14855
+ * `TnDialog` does — `tn-drawer` still binds `keydown` on its own panel and
14856
+ * does not.
14857
+ * - **A CDK dialog opened over an open panel hides the panel from assistive
14858
+ * technology.** CDK does this by sweeping the overlay container's SIBLINGS,
14859
+ * which no longer includes the panel, so the component tracks it — see
14860
+ * `dialogsAbove`.
14861
+ * - **A consumer no longer re-homes the overlay or overrides its `z-index` and
14862
+ * `pointer-events`.** There is no `z-index` on it any more; the CDK pane it
14863
+ * lives in carries the stacking.
14826
14864
  */
14827
14865
  declare class TnSidePanelComponent implements OnDestroy {
14828
14866
  private iconRegistry;
14829
14867
  private document;
14830
14868
  private destroyRef;
14869
+ private injector;
14870
+ private dialog;
14831
14871
  private overlayRef;
14832
14872
  private panelRef;
14833
14873
  private contentRef;
14834
14874
  protected initialized: _angular_core.WritableSignal<boolean>;
14875
+ /**
14876
+ * The CDK overlay currently hosting `overlayRef`'s element, or `null` while
14877
+ * the panel is closed (#322).
14878
+ *
14879
+ * **Created on open and disposed once the close has settled**, not once for
14880
+ * the component's lifetime. That is the whole mechanism: CDK decides stacking
14881
+ * by the order overlays ATTACH — `showPopover()` order in the top layer, and
14882
+ * `_updateStackingOrder()`'s move to the end of the container where the
14883
+ * popover API is missing — so an overlay created when the component was built
14884
+ * would stack by construction order, which for a panel rendered inside a
14885
+ * dialog is exactly backwards.
14886
+ *
14887
+ * Non-null is therefore also the answer to "is this panel currently one of
14888
+ * the overlays on screen", which is what `dialogsAbove` keys off.
14889
+ */
14890
+ private cdkOverlay;
14891
+ /** Escape handling for the overlay above, dropped with it. */
14892
+ private keydowns;
14893
+ /**
14894
+ * The CDK dialogs currently covering this panel (#322).
14895
+ *
14896
+ * The panel is hidden from assistive technology while this is non-empty,
14897
+ * which is what CDK's own `Dialog` does for everything outside the overlay
14898
+ * container — it sweeps the container's SIBLINGS, and a panel that now lives
14899
+ * INSIDE the container is not one. A dialog already open when the panel opens
14900
+ * is underneath it and never joins this; only dialogs that arrive afterwards
14901
+ * are above.
14902
+ *
14903
+ * A SET RATHER THAN A COUNT, and each dialog removes ITSELF. Nothing
14904
+ * unsubscribes a dialog's `closed` when the panel closes underneath it — the
14905
+ * panel cannot outlive its own release to do that — so with a count, a
14906
+ * dialog opened during one open and closed during the NEXT one decremented a
14907
+ * tally it had never contributed to, and put the panel back in the
14908
+ * accessibility tree with a live modal still stacked over it. Removing a
14909
+ * member that is not there is a no-op, which is the property a count does
14910
+ * not have.
14911
+ *
14912
+ * Emptied only when the last one goes, on the same reasoning as CDK's
14913
+ * `_removeOpenDialog`: two stacked dialogs closing one at a time must not
14914
+ * un-hide the panel while one is still covering it.
14915
+ */
14916
+ private dialogsAbove;
14835
14917
  /**
14836
14918
  * Whether the content region carries the tab stop, its role and its name
14837
14919
  * (#248) — which is NOT the same question as whether it currently overflows.
@@ -14844,10 +14926,14 @@ declare class TnSidePanelComponent implements OnDestroy {
14844
14926
  * answer is held true while the region has focus, and why `role` and
14845
14927
  * `aria-label` are gated on the same signal as `tabindex` rather than left on.
14846
14928
  *
14847
- * Read in `afterNextRender`, which is where the helper takes its first
14848
- * measurement — before the overlay is portaled to `<body>` below, which does
14849
- * not affect it: `.tn-side-panel__overlay` is `position: fixed; inset: 0`, so
14850
- * its size comes from the viewport rather than from its parent.
14929
+ * The helper's FIRST measurement reads a closed panel, which is
14930
+ * `display: none` since #322 and so reads as not overflowing. That is the
14931
+ * right answer for a panel nobody can reach yet, and it does not stick: the
14932
+ * helper's `ResizeObserver` fires when the overlay attaches and the region
14933
+ * gets a box, which is the same instrument that already answered a viewport
14934
+ * resize. Once open, `.tn-side-panel__overlay` is `position: fixed;
14935
+ * inset: 0`, so the region's size comes from the viewport rather than from
14936
+ * whichever CDK pane is hosting it.
14851
14937
  */
14852
14938
  protected contentKeyboardReachable: _angular_core.Signal<boolean>;
14853
14939
  open: _angular_core.ModelSignal<boolean>;
@@ -14949,19 +15035,75 @@ declare class TnSidePanelComponent implements OnDestroy {
14949
15035
  * fallback and raises no warning.
14950
15036
  */
14951
15037
  protected resolvedAriaLabel: _angular_core.Signal<string | null>;
15038
+ /**
15039
+ * Whether the overlay is out of the accessibility tree: closed, or covered by
15040
+ * a CDK dialog that opened over it (#322).
15041
+ *
15042
+ * The two are one attribute because they are one question, and rendering them
15043
+ * from separate bindings would mean the second could clear the first.
15044
+ */
15045
+ protected hiddenFromAssistiveTech: _angular_core.Signal<boolean>;
14952
15046
  private previouslyFocusedElement;
14953
15047
  /**
14954
15048
  * Decides when an open or a close counts as finished, so that the outputs
14955
15049
  * above fire exactly once per change whether or not a transition ran. A field
14956
15050
  * initializer rather than the constructor, because it registers an `effect`
14957
15051
  * and so needs an injection context.
15052
+ *
15053
+ * It is also what times the overlay's release (#322). The CDK overlay has to
15054
+ * outlive the CLOSE — disposing it puts the element back in this component's
15055
+ * view, where it is `display: none`, so doing that the moment `open` goes
15056
+ * false replaces the slide-out with a disappearance. "The close has settled"
15057
+ * is exactly the question this helper already answers, for a transition that
15058
+ * may never fire.
14958
15059
  */
14959
15060
  private lifecycle;
14960
15061
  constructor();
15062
+ /**
15063
+ * Put the overlay on screen, in a CDK overlay created now (#322).
15064
+ *
15065
+ * The three steps are ordered, and the order is the reason this is not two
15066
+ * bindings:
15067
+ *
15068
+ * 1. **Attach**, which is what fixes where the panel sits in the stack.
15069
+ * 2. **Read layout**, which forces the browser to compute the panel's closed
15070
+ * position in its new home. Without it the attach and the open class land
15071
+ * in one style update, the browser has no "before" to transition from, and
15072
+ * the panel appears rather than slides. A deliberate synchronous reflow,
15073
+ * and the only one: it happens once per open.
15074
+ * 3. **Open**, which is the change the transition runs on.
15075
+ *
15076
+ * Re-entrant on purpose. A panel reopened while its close is still animating
15077
+ * keeps the overlay it already has — the stack has not changed under it, and
15078
+ * `tnTransitionLifecycle` has already cancelled the close that would have
15079
+ * released it.
15080
+ */
15081
+ private showOverlay;
15082
+ /**
15083
+ * Give the CDK overlay back, once the close has finished animating.
15084
+ *
15085
+ * Disposing rather than detaching, so that the next open builds a new overlay
15086
+ * and takes a new place in the stack — see `cdkOverlay`. It restores the
15087
+ * element to this component's own view, where `display: none` keeps it out of
15088
+ * the way until then.
15089
+ */
15090
+ private releaseOverlay;
14961
15091
  ngOnDestroy(): void;
14962
15092
  protected dismiss(): void;
14963
15093
  protected onBackdropClick(): void;
14964
- protected onKeydown(event: KeyboardEvent): void;
15094
+ /**
15095
+ * Escape, delivered by CDK's `OverlayKeyboardDispatcher` (#322).
15096
+ *
15097
+ * It arrives only while this panel is the topmost attached overlay, so
15098
+ * nothing here has to decide whether the key was meant for something above or
15099
+ * below — which is what the `stopPropagation` this replaced was standing in
15100
+ * for, and it could only ever guard the direction it knew about.
15101
+ *
15102
+ * `preventDefault` rather than `stopPropagation`, matching CDK's own
15103
+ * `DialogRef`: the key has already been routed, and swallowing it would hide
15104
+ * it from a consumer listening at the document for their own reasons.
15105
+ */
15106
+ private onOverlayKeydown;
14965
15107
  protected onTransitionEnd(event: TransitionEvent): void;
14966
15108
  private restoreFocus;
14967
15109
  private registerMdiIcons;
@@ -14988,7 +15130,8 @@ declare class TnSidePanelHarness extends ComponentHarness {
14988
15130
  static hostSelector: string;
14989
15131
  static with(options?: SidePanelHarnessFilters): HarnessPredicate<TnSidePanelHarness>;
14990
15132
  /**
14991
- * Locate the overlay wrapper, which may be portaled to document.body.
15133
+ * Locate the overlay wrapper, which is portaled into a CDK overlay while the
15134
+ * panel is open and sits inside the host element while it is not.
14992
15135
  * Uses the data-tn-panel attribute to correlate the host with its overlay.
14993
15136
  */
14994
15137
  private getOverlay;