@genesislcap/foundation-ui 15.71.0 → 15.72.0-FUI-2629.7
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/custom-elements.json +852 -692
- package/dist/dts/actions-menu/actions-menu.d.ts +46 -0
- package/dist/dts/actions-menu/actions-menu.d.ts.map +1 -1
- package/dist/dts/actions-menu/actions-menu.styles.d.ts.map +1 -1
- package/dist/dts/actions-menu/actions-menu.template.d.ts +2 -2
- package/dist/dts/actions-menu/actions-menu.template.d.ts.map +1 -1
- package/dist/dts/actions-menu/ag-menu.styles.d.ts +16 -0
- package/dist/dts/actions-menu/ag-menu.styles.d.ts.map +1 -0
- package/dist/dts/actions-menu/index.d.ts +1 -0
- package/dist/dts/actions-menu/index.d.ts.map +1 -1
- package/dist/dts/filter-bar/filter-bar.utils.d.ts +1 -1
- package/dist/dts/react.d.ts +9 -9
- package/dist/dts/utils/popover-position.d.ts +22 -0
- package/dist/dts/utils/popover-position.d.ts.map +1 -0
- package/dist/esm/actions-menu/actions-menu.js +136 -19
- package/dist/esm/actions-menu/actions-menu.styles.js +40 -7
- package/dist/esm/actions-menu/actions-menu.template.js +69 -8
- package/dist/esm/actions-menu/ag-menu.styles.js +60 -0
- package/dist/esm/actions-menu/index.js +1 -0
- package/dist/esm/utils/popover-position.js +50 -0
- package/dist/foundation-ui.api.json +425 -5
- package/dist/foundation-ui.d.ts +64 -3
- package/dist/react.cjs +6 -6
- package/dist/react.mjs +5 -5
- package/package.json +17 -17
|
@@ -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.
|
|
@@ -9,18 +11,44 @@ export type ActionMenuItem = {
|
|
|
9
11
|
callback: (rowData: any) => void | any;
|
|
10
12
|
isDisabled?: (rowData: any) => boolean;
|
|
11
13
|
color?: string;
|
|
14
|
+
icon?: {
|
|
15
|
+
variant?: IconStyle;
|
|
16
|
+
name: string;
|
|
17
|
+
size?: FaSize;
|
|
18
|
+
};
|
|
12
19
|
};
|
|
20
|
+
/**
|
|
21
|
+
* A function of the row data returning the actions for that row (for row-scoped
|
|
22
|
+
* eligibility/permission filtering).
|
|
23
|
+
* @public
|
|
24
|
+
*/
|
|
25
|
+
export type ActionMenuItemsResolver = (rowData: any) => ActionMenuItem[];
|
|
26
|
+
/**
|
|
27
|
+
* The actions a grid column's Actions Menu shows: a fixed array, or a resolver per row.
|
|
28
|
+
* @public
|
|
29
|
+
*/
|
|
30
|
+
export type ActionMenuItems = ActionMenuItem[] | ActionMenuItemsResolver;
|
|
13
31
|
/**
|
|
14
32
|
* @tagname %%prefix%%-actions-menu
|
|
15
33
|
*/
|
|
16
34
|
export declare class ActionsMenu extends FoundationElement {
|
|
17
35
|
actions: ActionMenuItem[];
|
|
36
|
+
/**
|
|
37
|
+
* Resolves the actions per row instead of `actions`, from the row data in `definition`.
|
|
38
|
+
* @remarks Set from a function passed as the cell params' `actions`.
|
|
39
|
+
*/
|
|
40
|
+
actionsResolver?: ActionMenuItemsResolver;
|
|
18
41
|
isVertical: boolean;
|
|
19
42
|
addDefaultActions: boolean;
|
|
20
43
|
autoCloseOnAction: boolean;
|
|
21
44
|
classNames: string;
|
|
22
45
|
definition: any;
|
|
23
46
|
name: string;
|
|
47
|
+
/**
|
|
48
|
+
* When set, the opener renders this icon instead of the `name` text (e.g. `ellipsis`
|
|
49
|
+
* for an icon-only "kebab" opener).
|
|
50
|
+
*/
|
|
51
|
+
iconName: string;
|
|
24
52
|
open: boolean;
|
|
25
53
|
buttonAppearance: string;
|
|
26
54
|
hideDisabled: boolean;
|
|
@@ -28,12 +56,30 @@ export declare class ActionsMenu extends FoundationElement {
|
|
|
28
56
|
singleOption: ActionMenuItem;
|
|
29
57
|
actionsMenu: HTMLElement;
|
|
30
58
|
actionsOpener: HTMLElement;
|
|
59
|
+
private positionTracker?;
|
|
60
|
+
/** Set when the keyboard opens the menu, so focus moves into it as screen readers announce. */
|
|
61
|
+
private focusMenuOnOpen;
|
|
31
62
|
disconnectedCallback(): void;
|
|
32
63
|
private updateMenuPosition;
|
|
64
|
+
private startTrackingPosition;
|
|
65
|
+
private stopTrackingPosition;
|
|
33
66
|
protected definitionChanged(oldValue: any, newValue: any): void;
|
|
34
67
|
protected openChanged(): void;
|
|
35
68
|
toggleActionsMenuVisibility(): void;
|
|
69
|
+
/**
|
|
70
|
+
* Syncs `open` when the native `popover="auto"` light-dismiss (outside click / Escape) closes
|
|
71
|
+
* the vertical menu without going through `toggleActionsMenuVisibility()`.
|
|
72
|
+
*/
|
|
73
|
+
onPopoverToggle(event: Event): void;
|
|
74
|
+
/** Opens the icon-only opener from the keyboard, as a native button would. */
|
|
75
|
+
onIconOpenerKeydown(event: KeyboardEvent): boolean;
|
|
36
76
|
onActionMenuItemClick(callback: (rowData: any) => void | any): void;
|
|
77
|
+
/** Resolves an action's `isDisabled` for the current row. */
|
|
78
|
+
isActionDisabled(action: ActionMenuItem): boolean;
|
|
79
|
+
/** The actions for the current row: from `actionsResolver` when set, else `actions`. */
|
|
80
|
+
get resolvedActions(): ActionMenuItem[];
|
|
81
|
+
/** Whether the row has an action to show: an enabled one, or any when disabled ones show. */
|
|
82
|
+
get hasVisibleActions(): boolean;
|
|
37
83
|
get allActions(): ActionMenuItem[];
|
|
38
84
|
get rowData(): any;
|
|
39
85
|
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":"
|
|
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,UAAU,CAAC,EAAE,CAAC,OAAO,EAAE,GAAG,KAAK,OAAO,CAAC;IACvC,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,uBAAuB,GAAG,CAAC,OAAO,EAAE,GAAG,KAAK,cAAc,EAAE,CAAC;AAEzE;;;GAGG;AACH,MAAM,MAAM,eAAe,GAAG,cAAc,EAAE,GAAG,uBAAuB,CAAC;AAEzE;;GAEG;AACH,qBAAa,WAAY,SAAQ,iBAAiB;IACpC,OAAO,EAAE,cAAc,EAAE,CAAC;IACtC;;;OAGG;IACS,eAAe,CAAC,EAAE,uBAAuB,CAAC;IACD,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;IACzD,+FAA+F;IAC/F,OAAO,CAAC,eAAe,CAAS;IAEhC,oBAAoB,IAAI,IAAI;IAQ5B,OAAO,CAAC,kBAAkB;IAyB1B,OAAO,CAAC,qBAAqB;IAS7B,OAAO,CAAC,oBAAoB;IAK5B,SAAS,CAAC,iBAAiB,CAAC,QAAQ,EAAE,GAAG,EAAE,QAAQ,EAAE,GAAG;IA0DxD,SAAS,CAAC,WAAW;IAyBrB,2BAA2B;IAI3B;;;OAGG;IACH,eAAe,CAAC,KAAK,EAAE,KAAK;IAO5B,8EAA8E;IAC9E,mBAAmB,CAAC,KAAK,EAAE,aAAa,GAAG,OAAO;IAOlD,qBAAqB,CAAC,QAAQ,EAAE,CAAC,OAAO,KAAA,KAAK,IAAI,GAAG,GAAG;IAKvD,6DAA6D;IAC7D,gBAAgB,CAAC,MAAM,EAAE,cAAc,GAAG,OAAO;IAIjD,wFAAwF;IACxF,IAAI,eAAe,IAAI,cAAc,EAAE,CAEtC;IAED,6FAA6F;IAC7F,IAAI,iBAAiB,IAAI,OAAO,CAK/B;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;CAsB3B;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;
|
|
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;AAGpC,eAAO,MAAM,qBAAqB,GAChC,SAAS,wBAAwB,EACjC,YAAY,2BAA2B,KACtC,aA4HF,CAAC;AAEF,eAAO,MAAM,2BAA2B,GACtC,SAAS,wBAAwB,EACjC,YAAY,2BAA2B,KACtC,aAEF,CAAC"}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import type { ViewTemplate } from '@microsoft/fast-element';
|
|
2
2
|
import type { ActionsMenu } from './actions-menu';
|
|
3
|
-
export declare const menuTemplate: (prefix: string) => ViewTemplate<ActionsMenu
|
|
4
|
-
export declare const singleOptionTemplate: (prefix: string) => ViewTemplate<ActionsMenu
|
|
3
|
+
export declare const menuTemplate: (prefix: string) => ViewTemplate<ActionsMenu>;
|
|
4
|
+
export declare const singleOptionTemplate: (prefix: string) => ViewTemplate<ActionsMenu>;
|
|
5
5
|
export declare const foundationActionsMenuTemplate: ViewTemplate<ActionsMenu>;
|
|
6
6
|
//# sourceMappingURL=actions-menu.template.d.ts.map
|
|
@@ -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;
|
|
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;AA6DlD,eAAO,MAAM,YAAY,WAhDP,MAAM,KAAG,YAAY,CAAC,WAAW,CAmHlD,CAAC;AAEF,eAAO,MAAM,oBAAoB,WArHf,MAAM,KAAG,YAAY,CAAC,WAAW,CAqIlD,CAAC;AAEF,eAAO,MAAM,6BAA6B,EAAE,YAAY,CAAC,WAAW,CAOnE,CAAC"}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import type { ElementStyles } from '@microsoft/fast-element';
|
|
2
|
+
/**
|
|
3
|
+
* Styles a menu to match AG Grid's own menu (ag-menu / ag-menu-list / ag-menu-option), so a menu
|
|
4
|
+
* drawn over a grid looks like the grid's. AG Grid's `--ag-*` variables apply where they are set;
|
|
5
|
+
* elsewhere the design system's tokens do, with fallbacks for when neither is in scope.
|
|
6
|
+
*
|
|
7
|
+
* @remarks Shared by the vertical actions menu and grid-pro's right-click menu. Each adds its own
|
|
8
|
+
* layout (display, sizing) around these rules.
|
|
9
|
+
*
|
|
10
|
+
* @param menuSelector - Selects the menu surface. May be a selector list.
|
|
11
|
+
* @param itemSelector - Selects a menu item. Must be a single selector, as states are appended to it.
|
|
12
|
+
* @returns The menu surface and item styles.
|
|
13
|
+
* @public
|
|
14
|
+
*/
|
|
15
|
+
export declare const agMenuStyles: (menuSelector: string, itemSelector: string) => ElementStyles;
|
|
16
|
+
//# sourceMappingURL=ag-menu.styles.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ag-menu.styles.d.ts","sourceRoot":"","sources":["../../../src/actions-menu/ag-menu.styles.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,yBAAyB,CAAC;AAG7D;;;;;;;;;;;;GAYG;AACH,eAAO,MAAM,YAAY,GAAI,cAAc,MAAM,EAAE,cAAc,MAAM,KAAG,aA6CzE,CAAC"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/actions-menu/index.ts"],"names":[],"mappings":"AAAA,cAAc,uBAAuB,CAAC;AACtC,cAAc,yBAAyB,CAAC;AACxC,cAAc,gBAAgB,CAAC"}
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/actions-menu/index.ts"],"names":[],"mappings":"AAAA,cAAc,uBAAuB,CAAC;AACtC,cAAc,yBAAyB,CAAC;AACxC,cAAc,gBAAgB,CAAC;AAC/B,cAAc,kBAAkB,CAAC"}
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
export declare const mapType: (TYPE: string) => "boolean" | "number" | "
|
|
1
|
+
export declare const mapType: (TYPE: string) => "boolean" | "number" | "text" | "date" | "enum";
|
|
2
2
|
//# sourceMappingURL=filter-bar.utils.d.ts.map
|
package/dist/dts/react.d.ts
CHANGED
|
@@ -133,15 +133,6 @@ interface HTMLWCProps extends React.AriaAttributes {
|
|
|
133
133
|
onInput?(e: Event): void;
|
|
134
134
|
}
|
|
135
135
|
|
|
136
|
-
export declare const Accordion: React.ForwardRefExoticComponent<
|
|
137
|
-
React.PropsWithChildren<
|
|
138
|
-
Omit<PublicOf<AccordionWC>, 'children' | 'style'> &
|
|
139
|
-
HTMLWCProps & {
|
|
140
|
-
}
|
|
141
|
-
> & React.RefAttributes<AccordionWC>
|
|
142
|
-
>;
|
|
143
|
-
export type AccordionRef = AccordionWC;
|
|
144
|
-
|
|
145
136
|
export declare const AccordionItem: React.ForwardRefExoticComponent<
|
|
146
137
|
React.PropsWithChildren<
|
|
147
138
|
Omit<PublicOf<AccordionItemWC>, 'children' | 'style'> &
|
|
@@ -180,6 +171,15 @@ export declare const AiIndicator: React.ForwardRefExoticComponent<
|
|
|
180
171
|
>;
|
|
181
172
|
export type AiIndicatorRef = AiIndicatorWC;
|
|
182
173
|
|
|
174
|
+
export declare const Accordion: React.ForwardRefExoticComponent<
|
|
175
|
+
React.PropsWithChildren<
|
|
176
|
+
Omit<PublicOf<AccordionWC>, 'children' | 'style'> &
|
|
177
|
+
HTMLWCProps & {
|
|
178
|
+
}
|
|
179
|
+
> & React.RefAttributes<AccordionWC>
|
|
180
|
+
>;
|
|
181
|
+
export type AccordionRef = AccordionWC;
|
|
182
|
+
|
|
183
183
|
export declare const Anchor: React.ForwardRefExoticComponent<
|
|
184
184
|
React.PropsWithChildren<
|
|
185
185
|
Omit<PublicOf<AnchorWC>, 'children' | 'style'> &
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Keeps a Popover-API element anchored to its trigger, and reports back when the trigger has been
|
|
3
|
+
* removed from the DOM (e.g. AG Grid row virtualization recycling the row that owns it).
|
|
4
|
+
* @remarks Checks the trigger once per animation frame while started, and repositions only when
|
|
5
|
+
* the trigger or the viewport moved. Events alone miss moves: native `scroll` events don't cross
|
|
6
|
+
* shadow-DOM boundaries, and a grid re-sort moves a row by `transform`, which fires nothing on the
|
|
7
|
+
* rows that didn't change. Callers start it when the popover opens and stop it when it closes.
|
|
8
|
+
* @internal
|
|
9
|
+
*/
|
|
10
|
+
export declare class AnchoredPopoverPositionTracker {
|
|
11
|
+
private readonly anchor;
|
|
12
|
+
private readonly onReposition;
|
|
13
|
+
private readonly onAnchorDetached;
|
|
14
|
+
private view?;
|
|
15
|
+
private frame?;
|
|
16
|
+
private lastPosition?;
|
|
17
|
+
private readonly check;
|
|
18
|
+
constructor(anchor: HTMLElement, onReposition: () => void, onAnchorDetached: () => void);
|
|
19
|
+
start(): void;
|
|
20
|
+
stop(): void;
|
|
21
|
+
}
|
|
22
|
+
//# 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;;;;;;;;GAQG;AACH,qBAAa,8BAA8B;IAwBvC,OAAO,CAAC,QAAQ,CAAC,MAAM;IACvB,OAAO,CAAC,QAAQ,CAAC,YAAY;IAC7B,OAAO,CAAC,QAAQ,CAAC,gBAAgB;IAzBnC,OAAO,CAAC,IAAI,CAAC,CAAgB;IAC7B,OAAO,CAAC,KAAK,CAAC,CAAS;IACvB,OAAO,CAAC,YAAY,CAAC,CAAS;IAE9B,OAAO,CAAC,QAAQ,CAAC,KAAK,CAgBpB;gBAGiB,MAAM,EAAE,WAAW,EACnB,YAAY,EAAE,MAAM,IAAI,EACxB,gBAAgB,EAAE,MAAM,IAAI;IAG/C,KAAK,IAAI,IAAI;IAOb,IAAI,IAAI,IAAI;CAQb"}
|
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
import { __decorate } from "tslib";
|
|
2
|
-
import { attr, observable } from '@microsoft/fast-element';
|
|
2
|
+
import { attr, DOM, observable } from '@microsoft/fast-element';
|
|
3
3
|
import { FoundationElement } from '@microsoft/fast-foundation';
|
|
4
|
-
import { classNames } from '@microsoft/fast-web-utilities';
|
|
4
|
+
import { classNames, limit } 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
|
/**
|
|
@@ -17,24 +18,60 @@ export class ActionsMenu extends FoundationElement {
|
|
|
17
18
|
this.open = false;
|
|
18
19
|
this.hideDisabled = false;
|
|
19
20
|
this.hideMenuSingleOption = false;
|
|
21
|
+
/** Set when the keyboard opens the menu, so focus moves into it as screen readers announce. */
|
|
22
|
+
this.focusMenuOnOpen = false;
|
|
20
23
|
}
|
|
21
24
|
disconnectedCallback() {
|
|
22
25
|
var _a;
|
|
26
|
+
this.stopTrackingPosition();
|
|
23
27
|
if ((_a = this.actionsMenu) === null || _a === void 0 ? void 0 : _a.matches(':popover-open')) {
|
|
24
28
|
this.actionsMenu.hidePopover();
|
|
25
29
|
}
|
|
26
30
|
super.disconnectedCallback();
|
|
27
31
|
}
|
|
28
32
|
updateMenuPosition() {
|
|
29
|
-
const
|
|
30
|
-
this.actionsMenu
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
this.
|
|
33
|
+
const opener = this.actionsOpener.getBoundingClientRect();
|
|
34
|
+
const menu = this.actionsMenu;
|
|
35
|
+
menu.style.position = 'fixed';
|
|
36
|
+
menu.style.left = 'auto';
|
|
37
|
+
if (!this.isVertical) {
|
|
38
|
+
// The horizontal menu overlays its opener.
|
|
39
|
+
menu.style.top = `${opener.top}px`;
|
|
40
|
+
menu.style.right = `${window.innerWidth - opener.right}px`;
|
|
41
|
+
return;
|
|
42
|
+
}
|
|
43
|
+
// The vertical menu drops down below its opener, flips above when only that side fits, and is
|
|
44
|
+
// clamped to the viewport (scrolling when taller than it) so it never renders off-screen.
|
|
45
|
+
const { innerHeight, innerWidth } = window;
|
|
46
|
+
menu.style.maxHeight = `${innerHeight}px`;
|
|
47
|
+
const { width, height } = menu.getBoundingClientRect();
|
|
48
|
+
const fitsBelow = height <= innerHeight - opener.bottom;
|
|
49
|
+
const fitsAbove = height <= opener.top;
|
|
50
|
+
const top = fitsBelow || !fitsAbove ? opener.bottom : opener.top - height;
|
|
51
|
+
menu.style.top = `${limit(0, Math.max(innerHeight - height, 0), top)}px`;
|
|
52
|
+
menu.style.right = `${limit(0, Math.max(innerWidth - width, 0), innerWidth - opener.right)}px`;
|
|
53
|
+
}
|
|
54
|
+
startTrackingPosition() {
|
|
55
|
+
this.positionTracker = new AnchoredPopoverPositionTracker(this.actionsOpener, () => this.updateMenuPosition(), () => (this.open = false));
|
|
56
|
+
this.positionTracker.start();
|
|
57
|
+
}
|
|
58
|
+
stopTrackingPosition() {
|
|
59
|
+
var _a;
|
|
60
|
+
(_a = this.positionTracker) === null || _a === void 0 ? void 0 : _a.stop();
|
|
61
|
+
this.positionTracker = undefined;
|
|
34
62
|
}
|
|
35
63
|
definitionChanged(oldValue, newValue) {
|
|
36
64
|
var _a;
|
|
37
|
-
|
|
65
|
+
if (!newValue)
|
|
66
|
+
return;
|
|
67
|
+
if (typeof newValue.actions === 'function') {
|
|
68
|
+
this.actionsResolver = newValue.actions;
|
|
69
|
+
this.actions = [];
|
|
70
|
+
}
|
|
71
|
+
else {
|
|
72
|
+
this.actionsResolver = undefined;
|
|
73
|
+
this.actions = (_a = newValue.actions) !== null && _a !== void 0 ? _a : [];
|
|
74
|
+
}
|
|
38
75
|
delete this.definition.actions;
|
|
39
76
|
if (newValue.buttonText) {
|
|
40
77
|
this.name = newValue.buttonText;
|
|
@@ -44,6 +81,18 @@ export class ActionsMenu extends FoundationElement {
|
|
|
44
81
|
this.isVertical = newValue.isVertical;
|
|
45
82
|
delete this.definition.isVertical;
|
|
46
83
|
}
|
|
84
|
+
if (newValue.iconName) {
|
|
85
|
+
this.iconName = newValue.iconName;
|
|
86
|
+
delete this.definition.iconName;
|
|
87
|
+
}
|
|
88
|
+
if (newValue.addDefaultActions !== undefined) {
|
|
89
|
+
this.addDefaultActions = newValue.addDefaultActions;
|
|
90
|
+
delete this.definition.addDefaultActions;
|
|
91
|
+
}
|
|
92
|
+
if (newValue.hideDisabled !== undefined) {
|
|
93
|
+
this.hideDisabled = newValue.hideDisabled;
|
|
94
|
+
delete this.definition.hideDisabled;
|
|
95
|
+
}
|
|
47
96
|
if (newValue.buttonAppearance) {
|
|
48
97
|
this.buttonAppearance = newValue.buttonAppearance;
|
|
49
98
|
delete this.definition.buttonAppearance;
|
|
@@ -52,35 +101,98 @@ export class ActionsMenu extends FoundationElement {
|
|
|
52
101
|
this.hideMenuSingleOption = newValue.hideMenuSingleOption;
|
|
53
102
|
delete this.definition.hideMenuSingleOption;
|
|
54
103
|
}
|
|
104
|
+
// A grid refresh hands over the latest row data: close a menu the row no longer has actions
|
|
105
|
+
// for (its opener is about to hide), and follow a row that moved.
|
|
106
|
+
if (this.open) {
|
|
107
|
+
if (this.isVertical && !this.hasVisibleActions) {
|
|
108
|
+
this.open = false;
|
|
109
|
+
}
|
|
110
|
+
else {
|
|
111
|
+
DOM.queueUpdate(() => this.open && this.updateMenuPosition());
|
|
112
|
+
}
|
|
113
|
+
}
|
|
55
114
|
}
|
|
56
115
|
openChanged() {
|
|
57
|
-
var _a;
|
|
116
|
+
var _a, _b, _c, _d;
|
|
58
117
|
this.classNames = classNames(['visible', this.open], ['hidden', !this.open]);
|
|
59
118
|
if (this.open) {
|
|
60
119
|
this.updateMenuPosition();
|
|
61
120
|
this.actionsMenu.showPopover();
|
|
121
|
+
this.startTrackingPosition();
|
|
122
|
+
// The menu only takes its size once the class update above renders it.
|
|
123
|
+
DOM.queueUpdate(() => {
|
|
124
|
+
if (!this.open)
|
|
125
|
+
return;
|
|
126
|
+
this.updateMenuPosition();
|
|
127
|
+
if (this.focusMenuOnOpen)
|
|
128
|
+
this.actionsMenu.focus();
|
|
129
|
+
this.focusMenuOnOpen = false;
|
|
130
|
+
});
|
|
62
131
|
}
|
|
63
|
-
else
|
|
64
|
-
this.
|
|
132
|
+
else {
|
|
133
|
+
this.focusMenuOnOpen = false;
|
|
134
|
+
this.stopTrackingPosition();
|
|
135
|
+
const focusInMenu = (_a = this.actionsMenu) === null || _a === void 0 ? void 0 : _a.contains((_b = this.shadowRoot) === null || _b === void 0 ? void 0 : _b.activeElement);
|
|
136
|
+
if ((_c = this.actionsMenu) === null || _c === void 0 ? void 0 : _c.matches(':popover-open')) {
|
|
137
|
+
this.actionsMenu.hidePopover();
|
|
138
|
+
}
|
|
139
|
+
if (focusInMenu)
|
|
140
|
+
(_d = this.actionsOpener) === null || _d === void 0 ? void 0 : _d.focus();
|
|
65
141
|
}
|
|
66
142
|
}
|
|
67
143
|
toggleActionsMenuVisibility() {
|
|
68
144
|
this.open = !this.open;
|
|
69
145
|
}
|
|
146
|
+
/**
|
|
147
|
+
* Syncs `open` when the native `popover="auto"` light-dismiss (outside click / Escape) closes
|
|
148
|
+
* the vertical menu without going through `toggleActionsMenuVisibility()`.
|
|
149
|
+
*/
|
|
150
|
+
onPopoverToggle(event) {
|
|
151
|
+
const newState = event.newState;
|
|
152
|
+
if (newState) {
|
|
153
|
+
this.open = newState === 'open';
|
|
154
|
+
}
|
|
155
|
+
}
|
|
156
|
+
/** Opens the icon-only opener from the keyboard, as a native button would. */
|
|
157
|
+
onIconOpenerKeydown(event) {
|
|
158
|
+
if (event.key !== 'Enter' && event.key !== ' ')
|
|
159
|
+
return true;
|
|
160
|
+
this.focusMenuOnOpen = !this.open;
|
|
161
|
+
this.toggleActionsMenuVisibility();
|
|
162
|
+
return false;
|
|
163
|
+
}
|
|
70
164
|
onActionMenuItemClick(callback) {
|
|
71
165
|
if (this.autoCloseOnAction)
|
|
72
166
|
this.open = false;
|
|
73
167
|
callback(this.rowData);
|
|
74
168
|
}
|
|
75
|
-
|
|
169
|
+
/** Resolves an action's `isDisabled` for the current row. */
|
|
170
|
+
isActionDisabled(action) {
|
|
171
|
+
var _a;
|
|
172
|
+
return !!((_a = action.isDisabled) === null || _a === void 0 ? void 0 : _a.call(action, this.rowData));
|
|
173
|
+
}
|
|
174
|
+
/** The actions for the current row: from `actionsResolver` when set, else `actions`. */
|
|
175
|
+
get resolvedActions() {
|
|
76
176
|
var _a;
|
|
177
|
+
return (_a = (this.actionsResolver ? this.actionsResolver(this.rowData) : this.actions)) !== null && _a !== void 0 ? _a : [];
|
|
178
|
+
}
|
|
179
|
+
/** Whether the row has an action to show: an enabled one, or any when disabled ones show. */
|
|
180
|
+
get hasVisibleActions() {
|
|
181
|
+
const actions = this.resolvedActions;
|
|
182
|
+
return this.hideDisabled
|
|
183
|
+
? actions.some((action) => !this.isActionDisabled(action))
|
|
184
|
+
: actions.length > 0;
|
|
185
|
+
}
|
|
186
|
+
get allActions() {
|
|
77
187
|
const defaultActions = [
|
|
78
188
|
{
|
|
79
189
|
name: '✖',
|
|
80
190
|
callback: () => (this.open = false),
|
|
81
191
|
},
|
|
82
192
|
];
|
|
83
|
-
return this.addDefaultActions
|
|
193
|
+
return this.addDefaultActions
|
|
194
|
+
? [...this.resolvedActions, ...defaultActions]
|
|
195
|
+
: this.resolvedActions;
|
|
84
196
|
}
|
|
85
197
|
get rowData() {
|
|
86
198
|
if (!this.definition)
|
|
@@ -95,15 +207,14 @@ export class ActionsMenu extends FoundationElement {
|
|
|
95
207
|
return name;
|
|
96
208
|
}
|
|
97
209
|
getTemplate(prefix) {
|
|
210
|
+
// The vertical menu hides its opener entirely rather than open onto nothing actionable.
|
|
211
|
+
if (this.isVertical && !this.hasVisibleActions) {
|
|
212
|
+
return;
|
|
213
|
+
}
|
|
214
|
+
const enabledRows = this.resolvedActions.filter((action) => !this.isActionDisabled(action));
|
|
98
215
|
if (!this.hideMenuSingleOption) {
|
|
99
216
|
return menuTemplate(prefix);
|
|
100
217
|
}
|
|
101
|
-
const enabledRows = this.actions.filter((action) => {
|
|
102
|
-
if (!action.isDisabled) {
|
|
103
|
-
return true;
|
|
104
|
-
}
|
|
105
|
-
return !action.isDisabled(this.rowData);
|
|
106
|
-
});
|
|
107
218
|
this.singleOption = null;
|
|
108
219
|
if (enabledRows.length === 0) {
|
|
109
220
|
return;
|
|
@@ -118,6 +229,9 @@ export class ActionsMenu extends FoundationElement {
|
|
|
118
229
|
__decorate([
|
|
119
230
|
observable
|
|
120
231
|
], ActionsMenu.prototype, "actions", void 0);
|
|
232
|
+
__decorate([
|
|
233
|
+
observable
|
|
234
|
+
], ActionsMenu.prototype, "actionsResolver", void 0);
|
|
121
235
|
__decorate([
|
|
122
236
|
attr({ attribute: 'is-vertical', mode: 'boolean' })
|
|
123
237
|
], ActionsMenu.prototype, "isVertical", void 0);
|
|
@@ -136,6 +250,9 @@ __decorate([
|
|
|
136
250
|
__decorate([
|
|
137
251
|
attr
|
|
138
252
|
], ActionsMenu.prototype, "name", void 0);
|
|
253
|
+
__decorate([
|
|
254
|
+
attr({ attribute: 'icon-name' })
|
|
255
|
+
], ActionsMenu.prototype, "iconName", void 0);
|
|
139
256
|
__decorate([
|
|
140
257
|
attr({ attribute: 'open', mode: 'boolean' })
|
|
141
258
|
], ActionsMenu.prototype, "open", void 0);
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { css } from '@microsoft/fast-element';
|
|
2
|
+
import { agMenuStyles } from './ag-menu.styles';
|
|
2
3
|
export const actionsMenuBaseStyles = (context, definition) => css `
|
|
3
4
|
:host {
|
|
4
5
|
--actions-opener-height-multiplier: 0.7px;
|
|
@@ -21,11 +22,9 @@ export const actionsMenuBaseStyles = (context, definition) => css `
|
|
|
21
22
|
margin: 0;
|
|
22
23
|
}
|
|
23
24
|
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
z-index: 100;
|
|
28
|
-
}
|
|
25
|
+
/* The vertical menu follows AG Grid's menu, so it matches the grid it usually sits in.
|
|
26
|
+
Its box-sizing lets updateMenuPosition cap max-height at the viewport, border included. */
|
|
27
|
+
${agMenuStyles('.actions-vertical .actions-menu', '.actions-vertical .menu-item')}
|
|
29
28
|
|
|
30
29
|
.actions-menu:not(.hidden):hover {
|
|
31
30
|
display: inline-flex;
|
|
@@ -48,6 +47,31 @@ export const actionsMenuBaseStyles = (context, definition) => css `
|
|
|
48
47
|
);
|
|
49
48
|
}
|
|
50
49
|
|
|
50
|
+
:host([icon-name]) .actions-container {
|
|
51
|
+
justify-content: center;
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
/* The icon-only opener mirrors grid-pro's icon renderer: a bare icon with a hover chip. */
|
|
55
|
+
.actions-opener.icon-only {
|
|
56
|
+
align-items: center;
|
|
57
|
+
justify-content: center;
|
|
58
|
+
height: auto;
|
|
59
|
+
padding: 5px;
|
|
60
|
+
border-radius: 5px;
|
|
61
|
+
line-height: 1;
|
|
62
|
+
color: inherit;
|
|
63
|
+
cursor: pointer;
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
.actions-opener.icon-only:hover,
|
|
67
|
+
.actions-opener.icon-only.opened {
|
|
68
|
+
background-color: var(--neutral-stroke-hover);
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
.actions-opener.icon-only:focus-visible {
|
|
72
|
+
outline: calc(var(--focus-stroke-width) * 1px) solid var(--accent-fill-rest);
|
|
73
|
+
}
|
|
74
|
+
|
|
51
75
|
svg {
|
|
52
76
|
width: 100%;
|
|
53
77
|
height: 100%;
|
|
@@ -80,10 +104,19 @@ export const actionsMenuBaseStyles = (context, definition) => css `
|
|
|
80
104
|
min-height: 0;
|
|
81
105
|
}
|
|
82
106
|
|
|
107
|
+
/* The open menu is a flex column, so a flex-basis would override the AG row height. */
|
|
83
108
|
.actions-vertical .menu-item {
|
|
84
|
-
flex:
|
|
109
|
+
flex: none;
|
|
110
|
+
max-height: none;
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
.actions-vertical .menu-item::part(start) {
|
|
114
|
+
padding-left: calc(var(--ag-spacing, 4px) * 2);
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
.actions-vertical .menu-item [slot='start'] {
|
|
85
118
|
justify-content: center;
|
|
86
|
-
|
|
119
|
+
width: var(--ag-icon-size, 16px);
|
|
87
120
|
}
|
|
88
121
|
|
|
89
122
|
.actions-vertical .visible,
|
|
@@ -1,6 +1,42 @@
|
|
|
1
1
|
import { html, ref, repeat, when } from '@microsoft/fast-element';
|
|
2
2
|
import { getPrefix } from '../utils';
|
|
3
|
-
|
|
3
|
+
/**
|
|
4
|
+
* Builds a template once per prefix. The bindings that pick a template re-run on every grid
|
|
5
|
+
* refresh; returning the same instance keeps the rendered view (and an open menu) in place.
|
|
6
|
+
* @remarks Don't remove this cache. FAST compares a binding's returned template by identity and
|
|
7
|
+
* re-creates the view whenever it gets a different instance. grid-pro's renderer `refresh()` hands
|
|
8
|
+
* the menu new params on every row update, so without it a streaming row would tear down the
|
|
9
|
+
* rendered view on each tick: the open popover is removed, `actionsMenu`/`actionsOpener` refs
|
|
10
|
+
* point at fresh elements, and `open` stays `true` with nothing visible.
|
|
11
|
+
*/
|
|
12
|
+
const perPrefix = (build) => {
|
|
13
|
+
const templates = new Map();
|
|
14
|
+
return (prefix) => {
|
|
15
|
+
if (!templates.has(prefix))
|
|
16
|
+
templates.set(prefix, build(prefix));
|
|
17
|
+
return templates.get(prefix);
|
|
18
|
+
};
|
|
19
|
+
};
|
|
20
|
+
/**
|
|
21
|
+
* A bare icon opener (e.g. a "kebab"), styled like grid-pro's icon renderer rather than a button.
|
|
22
|
+
*/
|
|
23
|
+
const iconOpenerTemplate = perPrefix((prefix) => html `
|
|
24
|
+
<div
|
|
25
|
+
${ref('actionsOpener')}
|
|
26
|
+
class="actions-opener icon-only${(x) => (x.open ? ' opened' : '')}"
|
|
27
|
+
part="icon-opener"
|
|
28
|
+
role="button"
|
|
29
|
+
tabindex="0"
|
|
30
|
+
aria-label="${(x) => x.name}"
|
|
31
|
+
aria-haspopup="menu"
|
|
32
|
+
aria-expanded="${(x) => String(x.open)}"
|
|
33
|
+
@click=${(x) => x.toggleActionsMenuVisibility()}
|
|
34
|
+
@keydown=${(x, c) => x.onIconOpenerKeydown(c.event)}
|
|
35
|
+
>
|
|
36
|
+
<${prefix}-icon name="${(x) => x.iconName}" size="lg"></${prefix}-icon>
|
|
37
|
+
</div>
|
|
38
|
+
`);
|
|
39
|
+
const buttonOpenerTemplate = perPrefix((prefix) => html `
|
|
4
40
|
<${prefix}-button
|
|
5
41
|
${ref('actionsOpener')}
|
|
6
42
|
id="actiosnMenuTrigger"
|
|
@@ -15,32 +51,57 @@ export const menuTemplate = (prefix) => html `
|
|
|
15
51
|
${x.name}
|
|
16
52
|
`}
|
|
17
53
|
</${prefix}-button>
|
|
18
|
-
|
|
54
|
+
`);
|
|
55
|
+
export const menuTemplate = perPrefix((prefix) => html `
|
|
56
|
+
${(x) => (x.iconName ? iconOpenerTemplate(prefix) : buttonOpenerTemplate(prefix))}
|
|
57
|
+
<${prefix}-menu
|
|
58
|
+
${ref('actionsMenu')}
|
|
59
|
+
popover="${(x) => (x.isVertical ? 'auto' : 'manual')}"
|
|
60
|
+
class="actions-menu ${(x) => x.classNames}"
|
|
61
|
+
part="actions-menu"
|
|
62
|
+
@toggle=${(x, c) => x.onPopoverToggle(c.event)}
|
|
63
|
+
>
|
|
19
64
|
${repeat((x) => x.allActions, html `
|
|
20
|
-
${when((x, context) =>
|
|
65
|
+
${when((x, context) => context.parent.isActionDisabled(x), html `
|
|
21
66
|
<${prefix}-menu-item
|
|
22
67
|
class="menu-item"
|
|
23
68
|
tabindex="${(x, context) => context.index}"
|
|
24
69
|
disabled
|
|
25
70
|
style=${(x, ctx) => (ctx.parent.hideDisabled ? 'display:none' : '')}
|
|
26
71
|
>
|
|
72
|
+
${when((x) => x.icon, html `
|
|
73
|
+
<${prefix}-icon
|
|
74
|
+
name=${(x) => x.icon.name}
|
|
75
|
+
size=${(x) => x.icon.size}
|
|
76
|
+
variant=${(x) => x.icon.variant}
|
|
77
|
+
slot="start"
|
|
78
|
+
></${prefix}-icon>
|
|
79
|
+
`)}
|
|
27
80
|
${(x, ctx) => ctx.parent.getLabel(x.name)}
|
|
28
81
|
</${prefix}-menu-item>
|
|
29
82
|
`)}
|
|
30
|
-
${when((x, context) => !
|
|
83
|
+
${when((x, context) => !context.parent.isActionDisabled(x), html `
|
|
31
84
|
<${prefix}-menu-item
|
|
32
85
|
class="menu-item"
|
|
33
86
|
tabindex="${(x, context) => context.index}"
|
|
34
87
|
@click=${(x, context) => context.parent.onActionMenuItemClick(x.callback)}
|
|
35
88
|
style="${(x) => (x.color ? `color: ${x.color};` : '')}"
|
|
36
89
|
>
|
|
90
|
+
${when((x) => x.icon, html `
|
|
91
|
+
<${prefix}-icon
|
|
92
|
+
name=${(x) => x.icon.name}
|
|
93
|
+
size=${(x) => x.icon.size}
|
|
94
|
+
variant=${(x) => x.icon.variant}
|
|
95
|
+
slot="start"
|
|
96
|
+
></${prefix}-icon>
|
|
97
|
+
`)}
|
|
37
98
|
${(x, ctx) => ctx.parent.getLabel(x.name)}
|
|
38
99
|
</${prefix}-menu-item>
|
|
39
100
|
`)}
|
|
40
101
|
`, { positioning: true })}
|
|
41
102
|
</${prefix}-menu>
|
|
42
|
-
|
|
43
|
-
export const singleOptionTemplate = (prefix) => html `
|
|
103
|
+
`);
|
|
104
|
+
export const singleOptionTemplate = perPrefix((prefix) => html `
|
|
44
105
|
<${prefix}-button
|
|
45
106
|
appearance="${(x) => x.buttonAppearance}"
|
|
46
107
|
part="actions-opener"
|
|
@@ -49,12 +110,12 @@ export const singleOptionTemplate = (prefix) => html `
|
|
|
49
110
|
return x === null || x === void 0 ? void 0 : x.singleOption.callback(x.rowData);
|
|
50
111
|
}}
|
|
51
112
|
?disabled=${(x) => {
|
|
52
|
-
return
|
|
113
|
+
return x.isActionDisabled(x.singleOption);
|
|
53
114
|
}}
|
|
54
115
|
>
|
|
55
116
|
${(x) => x.getLabel(x === null || x === void 0 ? void 0 : x.singleOption.name)}
|
|
56
117
|
</${prefix}-button>
|
|
57
|
-
|
|
118
|
+
`);
|
|
58
119
|
export const foundationActionsMenuTemplate = html `
|
|
59
120
|
<div
|
|
60
121
|
class="actions-container${(x) => (x.isVertical ? ' actions-vertical' : '')}"
|