@genesislcap/foundation-ui 15.58.0 → 15.58.1-FUI-2629.5

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,4 +1,6 @@
1
+ import type { IconStyle } from '@fortawesome/fontawesome-svg-core';
1
2
  import { FoundationElement } from '@microsoft/fast-foundation';
3
+ import type { FaSize } from '../icon';
2
4
  /**
3
5
  * The Action Menu Item component.
4
6
  * @remarks Used within the Action Menu component.
@@ -7,20 +9,37 @@ import { FoundationElement } from '@microsoft/fast-foundation';
7
9
  export type ActionMenuItem = {
8
10
  name: string | ((rowData: any) => string);
9
11
  callback: (rowData: any) => void | any;
10
- isDisabled?: (rowData: any) => boolean;
12
+ /** A fixed flag, or a function of the row data (the grid row from the cell params). */
13
+ isDisabled?: boolean | ((rowData: any) => boolean);
11
14
  color?: string;
15
+ icon?: {
16
+ variant?: IconStyle;
17
+ name: string;
18
+ size?: FaSize;
19
+ };
12
20
  };
21
+ /**
22
+ * The actions shown by the Actions Menu: a fixed array, or a function of the row data returning
23
+ * one (for row-scoped eligibility/permission filtering).
24
+ * @public
25
+ */
26
+ export type ActionMenuItems = ActionMenuItem[] | ((rowData: any) => ActionMenuItem[]);
13
27
  /**
14
28
  * @tagname %%prefix%%-actions-menu
15
29
  */
16
30
  export declare class ActionsMenu extends FoundationElement {
17
- actions: ActionMenuItem[];
31
+ actions: ActionMenuItems;
18
32
  isVertical: boolean;
19
33
  addDefaultActions: boolean;
20
34
  autoCloseOnAction: boolean;
21
35
  classNames: string;
22
36
  definition: any;
23
37
  name: string;
38
+ /**
39
+ * When set, the opener renders this icon instead of the `name` text (e.g. `ellipsis`
40
+ * for an icon-only "kebab" opener).
41
+ */
42
+ iconName: string;
24
43
  open: boolean;
25
44
  buttonAppearance: string;
26
45
  hideDisabled: boolean;
@@ -28,12 +47,25 @@ export declare class ActionsMenu extends FoundationElement {
28
47
  singleOption: ActionMenuItem;
29
48
  actionsMenu: HTMLElement;
30
49
  actionsOpener: HTMLElement;
50
+ private positionTracker?;
31
51
  disconnectedCallback(): void;
32
52
  private updateMenuPosition;
53
+ private startTrackingPosition;
54
+ private stopTrackingPosition;
33
55
  protected definitionChanged(oldValue: any, newValue: any): void;
34
56
  protected openChanged(): void;
35
57
  toggleActionsMenuVisibility(): void;
58
+ /**
59
+ * Syncs `open` when the native `popover="auto"` light-dismiss (outside click / Escape) closes
60
+ * the vertical menu without going through `toggleActionsMenuVisibility()`.
61
+ */
62
+ onPopoverToggle(event: Event): void;
63
+ /** Opens the icon-only opener from the keyboard, as a native button would. */
64
+ onIconOpenerKeydown(event: KeyboardEvent): boolean;
36
65
  onActionMenuItemClick(callback: (rowData: any) => void | any): void;
66
+ /** Resolves an action's `isDisabled` flag or row-data function for the current row. */
67
+ isActionDisabled(action: ActionMenuItem): boolean;
68
+ get resolvedActions(): ActionMenuItem[];
37
69
  get allActions(): ActionMenuItem[];
38
70
  get rowData(): any;
39
71
  getLabel(name: string | ((rowData: any) => string)): string;
@@ -1 +1 @@
1
- {"version":3,"file":"actions-menu.d.ts","sourceRoot":"","sources":["../../../src/actions-menu/actions-menu.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,iBAAiB,EAAE,MAAM,4BAA4B,CAAC;AAS/D;;;;GAIG;AACH,MAAM,MAAM,cAAc,GAAG;IAC3B,IAAI,EAAE,MAAM,GAAG,CAAC,CAAC,OAAO,EAAE,GAAG,KAAK,MAAM,CAAC,CAAC;IAC1C,QAAQ,EAAE,CAAC,OAAO,EAAE,GAAG,KAAK,IAAI,GAAG,GAAG,CAAC;IACvC,UAAU,CAAC,EAAE,CAAC,OAAO,EAAE,GAAG,KAAK,OAAO,CAAC;IACvC,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB,CAAC;AAEF;;GAEG;AACH,qBAAa,WAAY,SAAQ,iBAAiB;IACpC,OAAO,EAAE,cAAc,EAAE,CAAC;IACe,UAAU,EAAE,OAAO,CAAS;IACpB,iBAAiB,EAAE,OAAO,CAAQ;IACjC,iBAAiB,EAAE,OAAO,CAAQ;IACpF,UAAU,EAAE,MAAM,CAAC;IACnB,UAAU,EAAE,GAAG,CAAC;IACtB,IAAI,SAAa;IACuB,IAAI,EAAE,OAAO,CAAS;IAC9D,gBAAgB,EAAE,MAAM,CAAC;IACwB,YAAY,EAAE,OAAO,CAAS;IACpB,oBAAoB,EAAE,OAAO,CACtF;IACI,YAAY,EAAE,cAAc,CAAC;IAEzC,WAAW,EAAG,WAAW,CAAC;IAC1B,aAAa,EAAG,WAAW,CAAC;IAE5B,oBAAoB,IAAI,IAAI;IAO5B,OAAO,CAAC,kBAAkB;IAQ1B,SAAS,CAAC,iBAAiB,CAAC,QAAQ,EAAE,GAAG,EAAE,QAAQ,EAAE,GAAG;IAyBxD,SAAS,CAAC,WAAW;IAWrB,2BAA2B;IAI3B,qBAAqB,CAAC,QAAQ,EAAE,CAAC,OAAO,KAAA,KAAK,IAAI,GAAG,GAAG;IAKvD,IAAI,UAAU,IAAI,cAAc,EAAE,CASjC;IAED,IAAI,OAAO,QAKV;IAED,QAAQ,CAAC,IAAI,EAAE,MAAM,GAAG,CAAC,CAAC,OAAO,EAAE,GAAG,KAAK,MAAM,CAAC;IAQlD,WAAW,CAAC,MAAM,EAAE,MAAM;CAsB3B;AAED;;;;;;GAMG;AACH,eAAO,MAAM,qBAAqB,2TAIhC,CAAC"}
1
+ {"version":3,"file":"actions-menu.d.ts","sourceRoot":"","sources":["../../../src/actions-menu/actions-menu.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,mCAAmC,CAAC;AAEnE,OAAO,EAAE,iBAAiB,EAAE,MAAM,4BAA4B,CAAC;AAE/D,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,SAAS,CAAC;AAStC;;;;GAIG;AACH,MAAM,MAAM,cAAc,GAAG;IAC3B,IAAI,EAAE,MAAM,GAAG,CAAC,CAAC,OAAO,EAAE,GAAG,KAAK,MAAM,CAAC,CAAC;IAC1C,QAAQ,EAAE,CAAC,OAAO,EAAE,GAAG,KAAK,IAAI,GAAG,GAAG,CAAC;IACvC,uFAAuF;IACvF,UAAU,CAAC,EAAE,OAAO,GAAG,CAAC,CAAC,OAAO,EAAE,GAAG,KAAK,OAAO,CAAC,CAAC;IACnD,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,IAAI,CAAC,EAAE;QACL,OAAO,CAAC,EAAE,SAAS,CAAC;QACpB,IAAI,EAAE,MAAM,CAAC;QACb,IAAI,CAAC,EAAE,MAAM,CAAC;KACf,CAAC;CACH,CAAC;AAEF;;;;GAIG;AACH,MAAM,MAAM,eAAe,GAAG,cAAc,EAAE,GAAG,CAAC,CAAC,OAAO,EAAE,GAAG,KAAK,cAAc,EAAE,CAAC,CAAC;AAEtF;;GAEG;AACH,qBAAa,WAAY,SAAQ,iBAAiB;IACpC,OAAO,EAAE,eAAe,CAAC;IACgB,UAAU,EAAE,OAAO,CAAS;IACpB,iBAAiB,EAAE,OAAO,CAAQ;IACjC,iBAAiB,EAAE,OAAO,CAAQ;IACpF,UAAU,EAAE,MAAM,CAAC;IACnB,UAAU,EAAE,GAAG,CAAC;IACtB,IAAI,SAAa;IACvB;;;OAGG;IAC+B,QAAQ,EAAE,MAAM,CAAC;IACL,IAAI,EAAE,OAAO,CAAS;IAC9D,gBAAgB,EAAE,MAAM,CAAC;IACwB,YAAY,EAAE,OAAO,CAAS;IACpB,oBAAoB,EAAE,OAAO,CACtF;IACI,YAAY,EAAE,cAAc,CAAC;IAEzC,WAAW,EAAG,WAAW,CAAC;IAC1B,aAAa,EAAG,WAAW,CAAC;IAE5B,OAAO,CAAC,eAAe,CAAC,CAAiC;IAEzD,oBAAoB,IAAI,IAAI;IAQ5B,OAAO,CAAC,kBAAkB;IAS1B,OAAO,CAAC,qBAAqB;IAS7B,OAAO,CAAC,oBAAoB;IAK5B,SAAS,CAAC,iBAAiB,CAAC,QAAQ,EAAE,GAAG,EAAE,QAAQ,EAAE,GAAG;IA0CxD,SAAS,CAAC,WAAW;IAerB,2BAA2B;IAI3B;;;OAGG;IACH,eAAe,CAAC,KAAK,EAAE,KAAK;IAO5B,8EAA8E;IAC9E,mBAAmB,CAAC,KAAK,EAAE,aAAa,GAAG,OAAO;IAMlD,qBAAqB,CAAC,QAAQ,EAAE,CAAC,OAAO,KAAA,KAAK,IAAI,GAAG,GAAG;IAKvD,uFAAuF;IACvF,gBAAgB,CAAC,MAAM,EAAE,cAAc,GAAG,OAAO;IAKjD,IAAI,eAAe,IAAI,cAAc,EAAE,CAGtC;IAED,IAAI,UAAU,IAAI,cAAc,EAAE,CAWjC;IAED,IAAI,OAAO,QAKV;IAED,QAAQ,CAAC,IAAI,EAAE,MAAM,GAAG,CAAC,CAAC,OAAO,EAAE,GAAG,KAAK,MAAM,CAAC;IAQlD,WAAW,CAAC,MAAM,EAAE,MAAM;CAyB3B;AAED;;;;;;GAMG;AACH,eAAO,MAAM,qBAAqB,2TAIhC,CAAC"}
@@ -1 +1 @@
1
- {"version":3,"file":"actions-menu.styles.d.ts","sourceRoot":"","sources":["../../../src/actions-menu/actions-menu.styles.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,yBAAyB,CAAC;AAE7D,OAAO,KAAK,EACV,wBAAwB,EACxB,2BAA2B,EAC5B,MAAM,4BAA4B,CAAC;AAEpC,eAAO,MAAM,qBAAqB,GAChC,SAAS,wBAAwB,EACjC,YAAY,2BAA2B,KACtC,aA4FF,CAAC;AAEF,eAAO,MAAM,2BAA2B,GACtC,SAAS,wBAAwB,EACjC,YAAY,2BAA2B,KACtC,aAEF,CAAC"}
1
+ {"version":3,"file":"actions-menu.styles.d.ts","sourceRoot":"","sources":["../../../src/actions-menu/actions-menu.styles.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,yBAAyB,CAAC;AAE7D,OAAO,KAAK,EACV,wBAAwB,EACxB,2BAA2B,EAC5B,MAAM,4BAA4B,CAAC;AAEpC,eAAO,MAAM,qBAAqB,GAChC,SAAS,wBAAwB,EACjC,YAAY,2BAA2B,KACtC,aAiKF,CAAC;AAEF,eAAO,MAAM,2BAA2B,GACtC,SAAS,wBAAwB,EACjC,YAAY,2BAA2B,KACtC,aAEF,CAAC"}
@@ -1 +1 @@
1
- {"version":3,"file":"actions-menu.template.d.ts","sourceRoot":"","sources":["../../../src/actions-menu/actions-menu.template.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAoB,YAAY,EAAE,MAAM,yBAAyB,CAAC;AAG9E,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,gBAAgB,CAAC;AAElD,eAAO,MAAM,YAAY,GAAI,QAAQ,MAAM,mCAoD1C,CAAC;AAEF,eAAO,MAAM,oBAAoB,GAAI,QAAQ,MAAM,mCAclD,CAAC;AAEF,eAAO,MAAM,6BAA6B,EAAE,YAAY,CAAC,WAAW,CAOnE,CAAC"}
1
+ {"version":3,"file":"actions-menu.template.d.ts","sourceRoot":"","sources":["../../../src/actions-menu/actions-menu.template.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAoB,YAAY,EAAE,MAAM,yBAAyB,CAAC;AAG9E,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,gBAAgB,CAAC;AAwClD,eAAO,MAAM,YAAY,GAAI,QAAQ,MAAM,mCAiE1C,CAAC;AAEF,eAAO,MAAM,oBAAoB,GAAI,QAAQ,MAAM,mCAclD,CAAC;AAEF,eAAO,MAAM,6BAA6B,EAAE,YAAY,CAAC,WAAW,CAOnE,CAAC"}
@@ -1,2 +1,2 @@
1
- export declare const mapType: (TYPE: string) => "boolean" | "number" | "date" | "text" | "enum";
1
+ export declare const mapType: (TYPE: string) => "boolean" | "number" | "text" | "date" | "enum";
2
2
  //# sourceMappingURL=filter-bar.utils.d.ts.map
@@ -133,14 +133,14 @@ interface HTMLWCProps extends React.AriaAttributes {
133
133
  onInput?(e: Event): void;
134
134
  }
135
135
 
136
- export declare const AccordionItem: React.ForwardRefExoticComponent<
136
+ export declare const Accordion: React.ForwardRefExoticComponent<
137
137
  React.PropsWithChildren<
138
- Omit<PublicOf<AccordionItemWC>, 'children' | 'style'> &
138
+ Omit<PublicOf<AccordionWC>, 'children' | 'style'> &
139
139
  HTMLWCProps & {
140
140
  }
141
- > & React.RefAttributes<AccordionItemWC>
141
+ > & React.RefAttributes<AccordionWC>
142
142
  >;
143
- export type AccordionItemRef = AccordionItemWC;
143
+ export type AccordionRef = AccordionWC;
144
144
 
145
145
  export declare const ActionsMenu: React.ForwardRefExoticComponent<
146
146
  React.PropsWithChildren<
@@ -151,14 +151,14 @@ export declare const ActionsMenu: React.ForwardRefExoticComponent<
151
151
  >;
152
152
  export type ActionsMenuRef = ActionsMenuWC;
153
153
 
154
- export declare const Accordion: React.ForwardRefExoticComponent<
154
+ export declare const AccordionItem: React.ForwardRefExoticComponent<
155
155
  React.PropsWithChildren<
156
- Omit<PublicOf<AccordionWC>, 'children' | 'style'> &
156
+ Omit<PublicOf<AccordionItemWC>, 'children' | 'style'> &
157
157
  HTMLWCProps & {
158
158
  }
159
- > & React.RefAttributes<AccordionWC>
159
+ > & React.RefAttributes<AccordionItemWC>
160
160
  >;
161
- export type AccordionRef = AccordionWC;
161
+ export type AccordionItemRef = AccordionItemWC;
162
162
 
163
163
  export declare const AiCriteriaSearch: React.ForwardRefExoticComponent<
164
164
  React.PropsWithChildren<
@@ -0,0 +1,26 @@
1
+ /**
2
+ * Walks up from `element`, crossing shadow-root boundaries via `.host`, collecting every
3
+ * scrollable ancestor (including the anchor's own document).
4
+ * @remarks Native `scroll` events are not `composed`, so they don't cross shadow-DOM boundaries
5
+ * the way `click`/`keydown` do — a listener on `document` never sees a shadow-DOM-nested
6
+ * viewport's own scroll. Callers must listen on each returned ancestor directly.
7
+ * @internal
8
+ */
9
+ export declare function findScrollableAncestors(element: HTMLElement): (HTMLElement | Document)[];
10
+ /**
11
+ * Keeps a Popover-API element anchored to its trigger while any of the trigger's scrollable
12
+ * ancestors scroll, and reports back when the trigger has been removed from the DOM (e.g. AG
13
+ * Grid row virtualization recycling the row that owns it).
14
+ * @internal
15
+ */
16
+ export declare class AnchoredPopoverPositionTracker {
17
+ private readonly anchor;
18
+ private readonly onReposition;
19
+ private readonly onAnchorDetached;
20
+ private ancestors;
21
+ private readonly handleScroll;
22
+ constructor(anchor: HTMLElement, onReposition: () => void, onAnchorDetached: () => void);
23
+ start(): void;
24
+ stop(): void;
25
+ }
26
+ //# sourceMappingURL=popover-position.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"popover-position.d.ts","sourceRoot":"","sources":["../../../src/utils/popover-position.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AACH,wBAAgB,uBAAuB,CAAC,OAAO,EAAE,WAAW,GAAG,CAAC,WAAW,GAAG,QAAQ,CAAC,EAAE,CA8BxF;AAED;;;;;GAKG;AACH,qBAAa,8BAA8B;IAYvC,OAAO,CAAC,QAAQ,CAAC,MAAM;IACvB,OAAO,CAAC,QAAQ,CAAC,YAAY;IAC7B,OAAO,CAAC,QAAQ,CAAC,gBAAgB;IAbnC,OAAO,CAAC,SAAS,CAAkC;IAEnD,OAAO,CAAC,QAAQ,CAAC,YAAY,CAM3B;gBAGiB,MAAM,EAAE,WAAW,EACnB,YAAY,EAAE,MAAM,IAAI,EACxB,gBAAgB,EAAE,MAAM,IAAI;IAG/C,KAAK,IAAI,IAAI;IAQb,IAAI,IAAI,IAAI;CAMb"}
@@ -2,6 +2,7 @@ import { __decorate } from "tslib";
2
2
  import { attr, observable } from '@microsoft/fast-element';
3
3
  import { FoundationElement } from '@microsoft/fast-foundation';
4
4
  import { classNames } from '@microsoft/fast-web-utilities';
5
+ import { AnchoredPopoverPositionTracker } from '../utils/popover-position';
5
6
  import { foundationActionsMenuStyles as styles } from './actions-menu.styles';
6
7
  import { singleOptionTemplate, menuTemplate, foundationActionsMenuTemplate as template, } from './actions-menu.template';
7
8
  /**
@@ -20,6 +21,7 @@ export class ActionsMenu extends FoundationElement {
20
21
  }
21
22
  disconnectedCallback() {
22
23
  var _a;
24
+ this.stopTrackingPosition();
23
25
  if ((_a = this.actionsMenu) === null || _a === void 0 ? void 0 : _a.matches(':popover-open')) {
24
26
  this.actionsMenu.hidePopover();
25
27
  }
@@ -28,13 +30,25 @@ export class ActionsMenu extends FoundationElement {
28
30
  updateMenuPosition() {
29
31
  const rect = this.actionsOpener.getBoundingClientRect();
30
32
  this.actionsMenu.style.position = 'fixed';
31
- this.actionsMenu.style.top = `${rect.top}px`;
33
+ // The vertical menu drops down below its opener; the horizontal one overlays it.
34
+ this.actionsMenu.style.top = `${this.isVertical ? rect.bottom : rect.top}px`;
32
35
  this.actionsMenu.style.left = 'auto';
33
36
  this.actionsMenu.style.right = `${window.innerWidth - rect.right}px`;
34
37
  }
38
+ startTrackingPosition() {
39
+ this.positionTracker = new AnchoredPopoverPositionTracker(this.actionsOpener, () => this.updateMenuPosition(), () => (this.open = false));
40
+ this.positionTracker.start();
41
+ }
42
+ stopTrackingPosition() {
43
+ var _a;
44
+ (_a = this.positionTracker) === null || _a === void 0 ? void 0 : _a.stop();
45
+ this.positionTracker = undefined;
46
+ }
35
47
  definitionChanged(oldValue, newValue) {
36
48
  var _a;
37
- this.actions = (_a = newValue === null || newValue === void 0 ? void 0 : newValue.actions) !== null && _a !== void 0 ? _a : [];
49
+ if (!newValue)
50
+ return;
51
+ this.actions = (_a = newValue.actions) !== null && _a !== void 0 ? _a : [];
38
52
  delete this.definition.actions;
39
53
  if (newValue.buttonText) {
40
54
  this.name = newValue.buttonText;
@@ -44,6 +58,18 @@ export class ActionsMenu extends FoundationElement {
44
58
  this.isVertical = newValue.isVertical;
45
59
  delete this.definition.isVertical;
46
60
  }
61
+ if (newValue.iconName) {
62
+ this.iconName = newValue.iconName;
63
+ delete this.definition.iconName;
64
+ }
65
+ if (newValue.addDefaultActions !== undefined) {
66
+ this.addDefaultActions = newValue.addDefaultActions;
67
+ delete this.definition.addDefaultActions;
68
+ }
69
+ if (newValue.hideDisabled !== undefined) {
70
+ this.hideDisabled = newValue.hideDisabled;
71
+ delete this.definition.hideDisabled;
72
+ }
47
73
  if (newValue.buttonAppearance) {
48
74
  this.buttonAppearance = newValue.buttonAppearance;
49
75
  delete this.definition.buttonAppearance;
@@ -59,28 +85,59 @@ export class ActionsMenu extends FoundationElement {
59
85
  if (this.open) {
60
86
  this.updateMenuPosition();
61
87
  this.actionsMenu.showPopover();
88
+ this.startTrackingPosition();
62
89
  }
63
- else if ((_a = this.actionsMenu) === null || _a === void 0 ? void 0 : _a.matches(':popover-open')) {
64
- this.actionsMenu.hidePopover();
90
+ else {
91
+ this.stopTrackingPosition();
92
+ if ((_a = this.actionsMenu) === null || _a === void 0 ? void 0 : _a.matches(':popover-open')) {
93
+ this.actionsMenu.hidePopover();
94
+ }
65
95
  }
66
96
  }
67
97
  toggleActionsMenuVisibility() {
68
98
  this.open = !this.open;
69
99
  }
100
+ /**
101
+ * Syncs `open` when the native `popover="auto"` light-dismiss (outside click / Escape) closes
102
+ * the vertical menu without going through `toggleActionsMenuVisibility()`.
103
+ */
104
+ onPopoverToggle(event) {
105
+ const newState = event.newState;
106
+ if (newState) {
107
+ this.open = newState === 'open';
108
+ }
109
+ }
110
+ /** Opens the icon-only opener from the keyboard, as a native button would. */
111
+ onIconOpenerKeydown(event) {
112
+ if (event.key !== 'Enter' && event.key !== ' ')
113
+ return true;
114
+ this.toggleActionsMenuVisibility();
115
+ return false;
116
+ }
70
117
  onActionMenuItemClick(callback) {
71
118
  if (this.autoCloseOnAction)
72
119
  this.open = false;
73
120
  callback(this.rowData);
74
121
  }
122
+ /** Resolves an action's `isDisabled` flag or row-data function for the current row. */
123
+ isActionDisabled(action) {
124
+ const { isDisabled } = action;
125
+ return typeof isDisabled === 'function' ? !!isDisabled(this.rowData) : !!isDisabled;
126
+ }
127
+ get resolvedActions() {
128
+ const actions = typeof this.actions === 'function' ? this.actions(this.rowData) : this.actions;
129
+ return actions !== null && actions !== void 0 ? actions : [];
130
+ }
75
131
  get allActions() {
76
- var _a;
77
132
  const defaultActions = [
78
133
  {
79
134
  name: '✖',
80
135
  callback: () => (this.open = false),
81
136
  },
82
137
  ];
83
- return this.addDefaultActions ? [...((_a = this.actions) !== null && _a !== void 0 ? _a : []), ...defaultActions] : this.actions;
138
+ return this.addDefaultActions
139
+ ? [...this.resolvedActions, ...defaultActions]
140
+ : this.resolvedActions;
84
141
  }
85
142
  get rowData() {
86
143
  if (!this.definition)
@@ -95,15 +152,17 @@ export class ActionsMenu extends FoundationElement {
95
152
  return name;
96
153
  }
97
154
  getTemplate(prefix) {
155
+ const enabledRows = this.resolvedActions.filter((action) => !this.isActionDisabled(action));
156
+ // The vertical menu hides its opener entirely rather than open onto nothing actionable.
157
+ const hasVisibleActions = this.hideDisabled
158
+ ? enabledRows.length > 0
159
+ : this.resolvedActions.length > 0;
160
+ if (this.isVertical && !hasVisibleActions) {
161
+ return;
162
+ }
98
163
  if (!this.hideMenuSingleOption) {
99
164
  return menuTemplate(prefix);
100
165
  }
101
- const enabledRows = this.actions.filter((action) => {
102
- if (!action.isDisabled) {
103
- return true;
104
- }
105
- return !action.isDisabled(this.rowData);
106
- });
107
166
  this.singleOption = null;
108
167
  if (enabledRows.length === 0) {
109
168
  return;
@@ -136,6 +195,9 @@ __decorate([
136
195
  __decorate([
137
196
  attr
138
197
  ], ActionsMenu.prototype, "name", void 0);
198
+ __decorate([
199
+ attr({ attribute: 'icon-name' })
200
+ ], ActionsMenu.prototype, "iconName", void 0);
139
201
  __decorate([
140
202
  attr({ attribute: 'open', mode: 'boolean' })
141
203
  ], ActionsMenu.prototype, "open", void 0);
@@ -21,10 +21,17 @@ export const actionsMenuBaseStyles = (context, definition) => css `
21
21
  margin: 0;
22
22
  }
23
23
 
24
+ /* The vertical menu follows AG Grid's context menu (ag-menu / ag-menu-list / ag-menu-option),
25
+ so it matches the grid it usually sits in. Outside a grid the --ag-* vars are unset and the
26
+ design system's own tokens apply. */
24
27
  .actions-vertical .actions-menu {
25
- padding: calc(var(--design-unit) * 1px);
26
- max-height: 175px;
27
- z-index: 100;
28
+ padding: var(--ag-spacing, 4px) 0;
29
+ background-color: var(--ag-menu-background-color, var(--fill-color));
30
+ border: var(--ag-menu-border, calc(var(--stroke-width) * 1px) solid var(--neutral-stroke-rest));
31
+ border-radius: var(--ag-border-radius, calc(var(--control-corner-radius) * 1px));
32
+ box-shadow: var(--ag-menu-shadow, var(--ag-popup-shadow, 0 2px 8px rgb(0 0 0 / 30%)));
33
+ color: var(--ag-menu-text-color, var(--neutral-foreground-rest));
34
+ font-family: var(--ag-font-family, var(--body-font));
28
35
  }
29
36
 
30
37
  .actions-menu:not(.hidden):hover {
@@ -48,6 +55,31 @@ export const actionsMenuBaseStyles = (context, definition) => css `
48
55
  );
49
56
  }
50
57
 
58
+ :host([icon-name]) .actions-container {
59
+ justify-content: center;
60
+ }
61
+
62
+ /* The icon-only opener mirrors grid-pro's icon renderer: a bare icon with a hover chip. */
63
+ .actions-opener.icon-only {
64
+ align-items: center;
65
+ justify-content: center;
66
+ height: auto;
67
+ padding: 5px;
68
+ border-radius: 5px;
69
+ line-height: 1;
70
+ color: inherit;
71
+ cursor: pointer;
72
+ }
73
+
74
+ .actions-opener.icon-only:hover,
75
+ .actions-opener.icon-only.opened {
76
+ background-color: var(--neutral-stroke-hover);
77
+ }
78
+
79
+ .actions-opener.icon-only:focus-visible {
80
+ outline: calc(var(--focus-stroke-width) * 1px) solid var(--accent-fill-rest);
81
+ }
82
+
51
83
  svg {
52
84
  width: 100%;
53
85
  height: 100%;
@@ -80,10 +112,47 @@ export const actionsMenuBaseStyles = (context, definition) => css `
80
112
  min-height: 0;
81
113
  }
82
114
 
115
+ /* The open menu is a flex column, so a flex-basis would override the AG row height. */
83
116
  .actions-vertical .menu-item {
84
- flex: 1 1 auto;
117
+ flex: none;
118
+ box-sizing: border-box;
119
+ height: calc(var(--ag-icon-size, 16px) + (var(--ag-spacing, 4px) + 2px) * 2);
120
+ max-height: none;
121
+ margin: 0;
122
+ background: transparent;
123
+ border: none;
124
+ border-radius: 0;
125
+ color: inherit;
126
+ font-family: inherit;
127
+ font-size: var(--ag-font-size, var(--type-ramp-base-font-size));
128
+ font-weight: 500;
129
+ }
130
+
131
+ .actions-vertical .menu-item:hover,
132
+ .actions-vertical .menu-item:focus {
133
+ background: var(--ag-row-hover-color, var(--neutral-fill-stealth-hover));
134
+ border: none;
135
+ }
136
+
137
+ .actions-vertical .menu-item[disabled] {
138
+ background: transparent;
139
+ opacity: 50%;
140
+ }
141
+
142
+ .actions-vertical .menu-item::part(start) {
143
+ padding-left: calc(var(--ag-spacing, 4px) * 2);
144
+ }
145
+
146
+ .actions-vertical .menu-item [slot='start'] {
85
147
  justify-content: center;
86
- margin: calc(var(--design-unit) * 1px);
148
+ width: var(--ag-icon-size, 16px);
149
+ }
150
+
151
+ /* AG's trailing shortcut and popup-pointer cells add 2 more spacings on the right. */
152
+ .actions-vertical .menu-item::part(content) {
153
+ margin-inline: 0;
154
+ padding-inline: calc(var(--ag-spacing, 4px) * 2) calc(var(--ag-spacing, 4px) * 4);
155
+ line-height: var(--ag-icon-size, 16px);
87
156
  }
88
157
 
89
158
  .actions-vertical .visible,
@@ -1,6 +1,25 @@
1
1
  import { html, ref, repeat, when } from '@microsoft/fast-element';
2
2
  import { getPrefix } from '../utils';
3
- export const menuTemplate = (prefix) => html `
3
+ /**
4
+ * A bare icon opener (e.g. a "kebab"), styled like grid-pro's icon renderer rather than a button.
5
+ */
6
+ const iconOpenerTemplate = (prefix) => html `
7
+ <div
8
+ ${ref('actionsOpener')}
9
+ class="actions-opener icon-only${(x) => (x.open ? ' opened' : '')}"
10
+ part="icon-opener"
11
+ role="button"
12
+ tabindex="0"
13
+ aria-label="${(x) => x.name}"
14
+ aria-haspopup="menu"
15
+ aria-expanded="${(x) => String(x.open)}"
16
+ @click=${(x) => x.toggleActionsMenuVisibility()}
17
+ @keydown=${(x, c) => x.onIconOpenerKeydown(c.event)}
18
+ >
19
+ <${prefix}-icon name="${(x) => x.iconName}" size="lg"></${prefix}-icon>
20
+ </div>
21
+ `;
22
+ const buttonOpenerTemplate = (prefix) => html `
4
23
  <${prefix}-button
5
24
  ${ref('actionsOpener')}
6
25
  id="actiosnMenuTrigger"
@@ -15,25 +34,50 @@ export const menuTemplate = (prefix) => html `
15
34
  ${x.name}
16
35
  `}
17
36
  </${prefix}-button>
18
- <${prefix}-menu ${ref('actionsMenu')} popover="manual" class="actions-menu ${(x) => x.classNames}" part="actions-menu">
37
+ `;
38
+ export const menuTemplate = (prefix) => html `
39
+ ${(x) => (x.iconName ? iconOpenerTemplate(prefix) : buttonOpenerTemplate(prefix))}
40
+ <${prefix}-menu
41
+ ${ref('actionsMenu')}
42
+ popover="${(x) => (x.isVertical ? 'auto' : 'manual')}"
43
+ class="actions-menu ${(x) => x.classNames}"
44
+ part="actions-menu"
45
+ @toggle=${(x, c) => x.onPopoverToggle(c.event)}
46
+ >
19
47
  ${repeat((x) => x.allActions, html `
20
- ${when((x, context) => x.isDisabled && x.isDisabled(context.parent.rowData), html `
48
+ ${when((x, context) => context.parent.isActionDisabled(x), html `
21
49
  <${prefix}-menu-item
22
50
  class="menu-item"
23
51
  tabindex="${(x, context) => context.index}"
24
52
  disabled
25
53
  style=${(x, ctx) => (ctx.parent.hideDisabled ? 'display:none' : '')}
26
54
  >
55
+ ${when((x) => x.icon, html `
56
+ <${prefix}-icon
57
+ name=${(x) => x.icon.name}
58
+ size=${(x) => x.icon.size}
59
+ variant=${(x) => x.icon.variant}
60
+ slot="start"
61
+ ></${prefix}-icon>
62
+ `)}
27
63
  ${(x, ctx) => ctx.parent.getLabel(x.name)}
28
64
  </${prefix}-menu-item>
29
65
  `)}
30
- ${when((x, context) => !x.isDisabled || !x.isDisabled(context.parent.rowData), html `
66
+ ${when((x, context) => !context.parent.isActionDisabled(x), html `
31
67
  <${prefix}-menu-item
32
68
  class="menu-item"
33
69
  tabindex="${(x, context) => context.index}"
34
70
  @click=${(x, context) => context.parent.onActionMenuItemClick(x.callback)}
35
71
  style="${(x) => (x.color ? `color: ${x.color};` : '')}"
36
72
  >
73
+ ${when((x) => x.icon, html `
74
+ <${prefix}-icon
75
+ name=${(x) => x.icon.name}
76
+ size=${(x) => x.icon.size}
77
+ variant=${(x) => x.icon.variant}
78
+ slot="start"
79
+ ></${prefix}-icon>
80
+ `)}
37
81
  ${(x, ctx) => ctx.parent.getLabel(x.name)}
38
82
  </${prefix}-menu-item>
39
83
  `)}
@@ -49,7 +93,7 @@ export const singleOptionTemplate = (prefix) => html `
49
93
  return x === null || x === void 0 ? void 0 : x.singleOption.callback(x.rowData);
50
94
  }}
51
95
  ?disabled=${(x) => {
52
- return (x === null || x === void 0 ? void 0 : x.singleOption.isDisabled) && (x === null || x === void 0 ? void 0 : x.singleOption.isDisabled(x.rowData));
96
+ return x.isActionDisabled(x.singleOption);
53
97
  }}
54
98
  >
55
99
  ${(x) => x.getLabel(x === null || x === void 0 ? void 0 : x.singleOption.name)}
@@ -0,0 +1,70 @@
1
+ /**
2
+ * Walks up from `element`, crossing shadow-root boundaries via `.host`, collecting every
3
+ * scrollable ancestor (including the anchor's own document).
4
+ * @remarks Native `scroll` events are not `composed`, so they don't cross shadow-DOM boundaries
5
+ * the way `click`/`keydown` do — a listener on `document` never sees a shadow-DOM-nested
6
+ * viewport's own scroll. Callers must listen on each returned ancestor directly.
7
+ * @internal
8
+ */
9
+ export function findScrollableAncestors(element) {
10
+ var _a;
11
+ const ancestors = [];
12
+ let node = element.parentNode;
13
+ while (node) {
14
+ if (node instanceof ShadowRoot) {
15
+ node = node.host;
16
+ continue;
17
+ }
18
+ if (node instanceof Document) {
19
+ ancestors.push(node);
20
+ break;
21
+ }
22
+ if (node instanceof HTMLElement) {
23
+ const style = (_a = node.ownerDocument.defaultView) === null || _a === void 0 ? void 0 : _a.getComputedStyle(node);
24
+ if (!style) {
25
+ node = node.parentNode;
26
+ continue;
27
+ }
28
+ if (/(auto|scroll|overlay)/.test(style.overflowY) ||
29
+ /(auto|scroll|overlay)/.test(style.overflowX)) {
30
+ ancestors.push(node);
31
+ }
32
+ }
33
+ node = node.parentNode;
34
+ }
35
+ return ancestors;
36
+ }
37
+ /**
38
+ * Keeps a Popover-API element anchored to its trigger while any of the trigger's scrollable
39
+ * ancestors scroll, and reports back when the trigger has been removed from the DOM (e.g. AG
40
+ * Grid row virtualization recycling the row that owns it).
41
+ * @internal
42
+ */
43
+ export class AnchoredPopoverPositionTracker {
44
+ constructor(anchor, onReposition, onAnchorDetached) {
45
+ this.anchor = anchor;
46
+ this.onReposition = onReposition;
47
+ this.onAnchorDetached = onAnchorDetached;
48
+ this.ancestors = [];
49
+ this.handleScroll = () => {
50
+ if (!this.anchor.isConnected) {
51
+ this.onAnchorDetached();
52
+ return;
53
+ }
54
+ this.onReposition();
55
+ };
56
+ }
57
+ start() {
58
+ this.stop();
59
+ this.ancestors = findScrollableAncestors(this.anchor);
60
+ for (const ancestor of this.ancestors) {
61
+ ancestor.addEventListener('scroll', this.handleScroll, { passive: true });
62
+ }
63
+ }
64
+ stop() {
65
+ for (const ancestor of this.ancestors) {
66
+ ancestor.removeEventListener('scroll', this.handleScroll);
67
+ }
68
+ this.ancestors = [];
69
+ }
70
+ }