@ni/nimble-components 21.6.2 → 21.6.3

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.
@@ -68,6 +68,11 @@ export declare class Dialog<CloseReason = void> extends FoundationElement {
68
68
  * @internal
69
69
  */
70
70
  cancelHandler(event: Event): boolean;
71
+ /**
72
+ * @internal
73
+ */
74
+ closeHandler(): void;
75
+ private doResolveShow;
71
76
  }
72
77
  export interface Dialog extends ARIAGlobalStatesAndProperties {
73
78
  }
@@ -61,8 +61,7 @@ export class Dialog extends FoundationElement {
61
61
  throw new Error('Dialog is not open');
62
62
  }
63
63
  this.dialogElement.close();
64
- this.resolveShow(reason);
65
- this.resolveShow = undefined;
64
+ this.doResolveShow(reason);
66
65
  }
67
66
  slottedFooterElementsChanged(_prev, next) {
68
67
  this.footerIsEmpty = !next?.length;
@@ -75,11 +74,29 @@ export class Dialog extends FoundationElement {
75
74
  event.preventDefault();
76
75
  }
77
76
  else {
78
- this.resolveShow(UserDismissed);
79
- this.resolveShow = undefined;
77
+ this.doResolveShow(UserDismissed);
80
78
  }
81
79
  return true;
82
80
  }
81
+ /**
82
+ * @internal
83
+ */
84
+ closeHandler() {
85
+ if (this.resolveShow) {
86
+ // If
87
+ // - the browser implements dialogs with the CloseWatcher API, and
88
+ // - the user presses ESC without first interacting with the dialog (e.g. clicking, scrolling),
89
+ // the cancel event is not fired, but the close event still is, and the dialog just closes.
90
+ this.doResolveShow(UserDismissed);
91
+ }
92
+ }
93
+ doResolveShow(reason) {
94
+ if (!this.resolveShow) {
95
+ throw new Error('Do not call doResolveShow unless there is a promise to resolve');
96
+ }
97
+ this.resolveShow(reason);
98
+ this.resolveShow = undefined;
99
+ }
83
100
  }
84
101
  // We want the member to match the name of the constant
85
102
  // eslint-disable-next-line @typescript-eslint/naming-convention
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/dialog/index.ts"],"names":[],"mappings":"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","sourcesContent":["import { attr, observable } from '@microsoft/fast-element';\nimport {\n applyMixins,\n ARIAGlobalStatesAndProperties,\n DesignSystem,\n FoundationElement\n} from '@microsoft/fast-foundation';\nimport { UserDismissed } from '../patterns/dialog/types';\nimport { styles } from './styles';\nimport { template } from './template';\n\nexport { UserDismissed };\n\ndeclare global {\n interface HTMLElementTagNameMap {\n 'nimble-dialog': Dialog;\n }\n}\n\n/**\n * This is a workaround for an incomplete definition of the native dialog element. Remove when using Typescript >=4.8.3.\n * https://github.com/microsoft/TypeScript/issues/48267\n * @internal\n */\nexport interface ExtendedDialog extends HTMLDialogElement {\n showModal(): void;\n close(): void;\n}\n\n/**\n * A nimble-styled dialog.\n */\n// eslint-disable-next-line @typescript-eslint/no-invalid-void-type\nexport class Dialog<CloseReason = void> extends FoundationElement {\n // We want the member to match the name of the constant\n // eslint-disable-next-line @typescript-eslint/naming-convention\n public static readonly UserDismissed = UserDismissed;\n\n /**\n * @public\n * @description\n * Prevents dismissing the dialog via the Escape key\n */\n @attr({ attribute: 'prevent-dismiss', mode: 'boolean' })\n public preventDismiss = false;\n\n /**\n * @public\n * @description\n * Hides the header of the dialog.\n */\n @attr({ attribute: 'header-hidden', mode: 'boolean' })\n public headerHidden = false;\n\n /**\n * @public\n * @description\n * Hides the footer of the dialog.\n */\n @attr({ attribute: 'footer-hidden', mode: 'boolean' })\n public footerHidden = false;\n\n /**\n * The ref to the internal dialog element.\n *\n * @internal\n */\n public readonly dialogElement!: ExtendedDialog;\n\n /** @internal */\n @observable\n public footerIsEmpty = true;\n\n /** @internal */\n @observable\n public readonly slottedFooterElements?: HTMLElement[];\n\n /**\n * True if the dialog is open/showing, false otherwise\n */\n public get open(): boolean {\n return this.resolveShow !== undefined;\n }\n\n private resolveShow?: (reason: CloseReason | UserDismissed) => void;\n\n /**\n * Opens the dialog\n * @returns Promise that is resolved when the dialog is closed. The value of the resolved Promise is the reason value passed to the close() method, or UserDismissed if the dialog was closed via the ESC key.\n */\n public async show(): Promise<CloseReason | UserDismissed> {\n if (this.open) {\n throw new Error('Dialog is already open');\n }\n this.dialogElement.showModal();\n return new Promise((resolve, _reject) => {\n this.resolveShow = resolve;\n });\n }\n\n /**\n * Closes the dialog\n * @param reason An optional value indicating how/why the dialog was closed.\n */\n public close(reason: CloseReason): void {\n if (!this.open) {\n throw new Error('Dialog is not open');\n }\n this.dialogElement.close();\n this.resolveShow!(reason);\n this.resolveShow = undefined;\n }\n\n public slottedFooterElementsChanged(\n _prev: HTMLElement[] | undefined,\n next: HTMLElement[] | undefined\n ): void {\n this.footerIsEmpty = !next?.length;\n }\n\n /**\n * @internal\n */\n public cancelHandler(event: Event): boolean {\n if (this.preventDismiss) {\n event.preventDefault();\n } else {\n this.resolveShow!(UserDismissed);\n this.resolveShow = undefined;\n }\n return true;\n }\n}\n\n// eslint-disable-next-line @typescript-eslint/no-empty-interface\nexport interface Dialog extends ARIAGlobalStatesAndProperties {}\napplyMixins(Dialog, ARIAGlobalStatesAndProperties);\n\nconst nimbleDialog = Dialog.compose({\n baseName: 'dialog',\n template,\n styles,\n baseClass: Dialog\n});\n\nDesignSystem.getOrCreate().withPrefix('nimble').register(nimbleDialog());\nexport const dialogTag = 'nimble-dialog';\n"]}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/dialog/index.ts"],"names":[],"mappings":";AAAA,OAAO,EAAE,IAAI,EAAE,UAAU,EAAE,MAAM,yBAAyB,CAAC;AAC3D,OAAO,EACH,WAAW,EACX,6BAA6B,EAC7B,YAAY,EACZ,iBAAiB,EACpB,MAAM,4BAA4B,CAAC;AACpC,OAAO,EAAE,aAAa,EAAE,MAAM,0BAA0B,CAAC;AACzD,OAAO,EAAE,MAAM,EAAE,MAAM,UAAU,CAAC;AAClC,OAAO,EAAE,QAAQ,EAAE,MAAM,YAAY,CAAC;AAEtC,OAAO,EAAE,aAAa,EAAE,CAAC;AAkBzB;;GAEG;AACH,mEAAmE;AACnE,MAAM,OAAO,MAA2B,SAAQ,iBAAiB;IAAjE;;QAKI;;;;WAIG;QAEI,mBAAc,GAAG,KAAK,CAAC;QAE9B;;;;WAIG;QAEI,iBAAY,GAAG,KAAK,CAAC;QAE5B;;;;WAIG;QAEI,iBAAY,GAAG,KAAK,CAAC;QAS5B,gBAAgB;QAET,kBAAa,GAAG,IAAI,CAAC;IAkFhC,CAAC;IA5EG;;OAEG;IACH,IAAW,IAAI;QACX,OAAO,IAAI,CAAC,WAAW,KAAK,SAAS,CAAC;IAC1C,CAAC;IAID;;;OAGG;IACI,KAAK,CAAC,IAAI;QACb,IAAI,IAAI,CAAC,IAAI,EAAE;YACX,MAAM,IAAI,KAAK,CAAC,wBAAwB,CAAC,CAAC;SAC7C;QACD,IAAI,CAAC,aAAa,CAAC,SAAS,EAAE,CAAC;QAC/B,OAAO,IAAI,OAAO,CAAC,CAAC,OAAO,EAAE,OAAO,EAAE,EAAE;YACpC,IAAI,CAAC,WAAW,GAAG,OAAO,CAAC;QAC/B,CAAC,CAAC,CAAC;IACP,CAAC;IAED;;;OAGG;IACI,KAAK,CAAC,MAAmB;QAC5B,IAAI,CAAC,IAAI,CAAC,IAAI,EAAE;YACZ,MAAM,IAAI,KAAK,CAAC,oBAAoB,CAAC,CAAC;SACzC;QACD,IAAI,CAAC,aAAa,CAAC,KAAK,EAAE,CAAC;QAC3B,IAAI,CAAC,aAAa,CAAC,MAAM,CAAC,CAAC;IAC/B,CAAC;IAEM,4BAA4B,CAC/B,KAAgC,EAChC,IAA+B;QAE/B,IAAI,CAAC,aAAa,GAAG,CAAC,IAAI,EAAE,MAAM,CAAC;IACvC,CAAC;IAED;;OAEG;IACI,aAAa,CAAC,KAAY;QAC7B,IAAI,IAAI,CAAC,cAAc,EAAE;YACrB,KAAK,CAAC,cAAc,EAAE,CAAC;SAC1B;aAAM;YACH,IAAI,CAAC,aAAa,CAAC,aAAa,CAAC,CAAC;SACrC;QACD,OAAO,IAAI,CAAC;IAChB,CAAC;IAED;;OAEG;IACI,YAAY;QACf,IAAI,IAAI,CAAC,WAAW,EAAE;YAClB,KAAK;YACL,kEAAkE;YAClE,+FAA+F;YAC/F,2FAA2F;YAC3F,IAAI,CAAC,aAAa,CAAC,aAAa,CAAC,CAAC;SACrC;IACL,CAAC;IAEO,aAAa,CAAC,MAAmC;QACrD,IAAI,CAAC,IAAI,CAAC,WAAW,EAAE;YACnB,MAAM,IAAI,KAAK,CACX,gEAAgE,CACnE,CAAC;SACL;QACD,IAAI,CAAC,WAAW,CAAC,MAAM,CAAC,CAAC;QACzB,IAAI,CAAC,WAAW,GAAG,SAAS,CAAC;IACjC,CAAC;;AAtHD,uDAAuD;AACvD,gEAAgE;AACzC,oBAAa,GAAG,aAAa,CAAC;AAQrD;IADC,IAAI,CAAC,EAAE,SAAS,EAAE,iBAAiB,EAAE,IAAI,EAAE,SAAS,EAAE,CAAC;8CAC1B;AAQ9B;IADC,IAAI,CAAC,EAAE,SAAS,EAAE,eAAe,EAAE,IAAI,EAAE,SAAS,EAAE,CAAC;4CAC1B;AAQ5B;IADC,IAAI,CAAC,EAAE,SAAS,EAAE,eAAe,EAAE,IAAI,EAAE,SAAS,EAAE,CAAC;4CAC1B;AAW5B;IADC,UAAU;6CACiB;AAI5B;IADC,UAAU;qDAC2C;AAkF1D,WAAW,CAAC,MAAM,EAAE,6BAA6B,CAAC,CAAC;AAEnD,MAAM,YAAY,GAAG,MAAM,CAAC,OAAO,CAAC;IAChC,QAAQ,EAAE,QAAQ;IAClB,QAAQ;IACR,MAAM;IACN,SAAS,EAAE,MAAM;CACpB,CAAC,CAAC;AAEH,YAAY,CAAC,WAAW,EAAE,CAAC,UAAU,CAAC,QAAQ,CAAC,CAAC,QAAQ,CAAC,YAAY,EAAE,CAAC,CAAC;AACzE,MAAM,CAAC,MAAM,SAAS,GAAG,eAAe,CAAC","sourcesContent":["import { attr, observable } from '@microsoft/fast-element';\nimport {\n applyMixins,\n ARIAGlobalStatesAndProperties,\n DesignSystem,\n FoundationElement\n} from '@microsoft/fast-foundation';\nimport { UserDismissed } from '../patterns/dialog/types';\nimport { styles } from './styles';\nimport { template } from './template';\n\nexport { UserDismissed };\n\ndeclare global {\n interface HTMLElementTagNameMap {\n 'nimble-dialog': Dialog;\n }\n}\n\n/**\n * This is a workaround for an incomplete definition of the native dialog element. Remove when using Typescript >=4.8.3.\n * https://github.com/microsoft/TypeScript/issues/48267\n * @internal\n */\nexport interface ExtendedDialog extends HTMLDialogElement {\n showModal(): void;\n close(): void;\n}\n\n/**\n * A nimble-styled dialog.\n */\n// eslint-disable-next-line @typescript-eslint/no-invalid-void-type\nexport class Dialog<CloseReason = void> extends FoundationElement {\n // We want the member to match the name of the constant\n // eslint-disable-next-line @typescript-eslint/naming-convention\n public static readonly UserDismissed = UserDismissed;\n\n /**\n * @public\n * @description\n * Prevents dismissing the dialog via the Escape key\n */\n @attr({ attribute: 'prevent-dismiss', mode: 'boolean' })\n public preventDismiss = false;\n\n /**\n * @public\n * @description\n * Hides the header of the dialog.\n */\n @attr({ attribute: 'header-hidden', mode: 'boolean' })\n public headerHidden = false;\n\n /**\n * @public\n * @description\n * Hides the footer of the dialog.\n */\n @attr({ attribute: 'footer-hidden', mode: 'boolean' })\n public footerHidden = false;\n\n /**\n * The ref to the internal dialog element.\n *\n * @internal\n */\n public readonly dialogElement!: ExtendedDialog;\n\n /** @internal */\n @observable\n public footerIsEmpty = true;\n\n /** @internal */\n @observable\n public readonly slottedFooterElements?: HTMLElement[];\n\n /**\n * True if the dialog is open/showing, false otherwise\n */\n public get open(): boolean {\n return this.resolveShow !== undefined;\n }\n\n private resolveShow?: (reason: CloseReason | UserDismissed) => void;\n\n /**\n * Opens the dialog\n * @returns Promise that is resolved when the dialog is closed. The value of the resolved Promise is the reason value passed to the close() method, or UserDismissed if the dialog was closed via the ESC key.\n */\n public async show(): Promise<CloseReason | UserDismissed> {\n if (this.open) {\n throw new Error('Dialog is already open');\n }\n this.dialogElement.showModal();\n return new Promise((resolve, _reject) => {\n this.resolveShow = resolve;\n });\n }\n\n /**\n * Closes the dialog\n * @param reason An optional value indicating how/why the dialog was closed.\n */\n public close(reason: CloseReason): void {\n if (!this.open) {\n throw new Error('Dialog is not open');\n }\n this.dialogElement.close();\n this.doResolveShow(reason);\n }\n\n public slottedFooterElementsChanged(\n _prev: HTMLElement[] | undefined,\n next: HTMLElement[] | undefined\n ): void {\n this.footerIsEmpty = !next?.length;\n }\n\n /**\n * @internal\n */\n public cancelHandler(event: Event): boolean {\n if (this.preventDismiss) {\n event.preventDefault();\n } else {\n this.doResolveShow(UserDismissed);\n }\n return true;\n }\n\n /**\n * @internal\n */\n public closeHandler(): void {\n if (this.resolveShow) {\n // If\n // - the browser implements dialogs with the CloseWatcher API, and\n // - the user presses ESC without first interacting with the dialog (e.g. clicking, scrolling),\n // the cancel event is not fired, but the close event still is, and the dialog just closes.\n this.doResolveShow(UserDismissed);\n }\n }\n\n private doResolveShow(reason: CloseReason | UserDismissed): void {\n if (!this.resolveShow) {\n throw new Error(\n 'Do not call doResolveShow unless there is a promise to resolve'\n );\n }\n this.resolveShow(reason);\n this.resolveShow = undefined;\n }\n}\n\n// eslint-disable-next-line @typescript-eslint/no-empty-interface\nexport interface Dialog extends ARIAGlobalStatesAndProperties {}\napplyMixins(Dialog, ARIAGlobalStatesAndProperties);\n\nconst nimbleDialog = Dialog.compose({\n baseName: 'dialog',\n template,\n styles,\n baseClass: Dialog\n});\n\nDesignSystem.getOrCreate().withPrefix('nimble').register(nimbleDialog());\nexport const dialogTag = 'nimble-dialog';\n"]}
@@ -1,10 +1,11 @@
1
1
  import { css } from '@microsoft/fast-element';
2
2
  import { display } from '@microsoft/fast-foundation';
3
- import { applicationBackgroundColor, standardPadding, actionRgbPartialColor, bodyFont, bodyFontColor, titlePlus1Font, titlePlus1FontColor, smallPadding, subtitleFont, subtitleFontColor, elevation3BoxShadow, dialogSmallWidth, dialogSmallHeight, dialogSmallMaxHeight } from '../theme-provider/design-tokens';
3
+ import { applicationBackgroundColor, standardPadding, actionRgbPartialColor, bodyFont, bodyFontColor, titlePlus1Font, titlePlus1FontColor, smallPadding, subtitleFont, subtitleFontColor, elevation3BoxShadow, dialogSmallWidth, dialogSmallHeight, dialogSmallMaxHeight, borderHoverColor } from '../theme-provider/design-tokens';
4
4
  import { modalBackdropColorThemeColorStatic, modalBackdropColorThemeDarkStatic, modalBackdropColorThemeLightStatic } from '../theme-provider/design-tokens-static';
5
5
  import { Theme } from '../theme-provider/types';
6
6
  import { themeBehavior } from '../utilities/style/theme';
7
7
  import { accessiblyHidden } from '../utilities/style/accessibly-hidden';
8
+ import { focusVisible } from '../utilities/style/focus';
8
9
  export const styles = css `
9
10
  ${display('grid')}
10
11
 
@@ -23,6 +24,10 @@ export const styles = css `
23
24
  display: flex;
24
25
  }
25
26
 
27
+ dialog${focusVisible} {
28
+ outline: 2px solid ${borderHoverColor};
29
+ }
30
+
26
31
  header {
27
32
  min-height: 48px;
28
33
  padding: 24px 24px 0px 24px;
@@ -1 +1 @@
1
- {"version":3,"file":"styles.js","sourceRoot":"","sources":["../../../src/dialog/styles.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,GAAG,EAAE,MAAM,yBAAyB,CAAC;AAC9C,OAAO,EAAE,OAAO,EAAE,MAAM,4BAA4B,CAAC;AAErD,OAAO,EACH,0BAA0B,EAC1B,eAAe,EACf,qBAAqB,EACrB,QAAQ,EACR,aAAa,EACb,cAAc,EACd,mBAAmB,EACnB,YAAY,EACZ,YAAY,EACZ,iBAAiB,EACjB,mBAAmB,EACnB,gBAAgB,EAChB,iBAAiB,EACjB,oBAAoB,EACvB,MAAM,iCAAiC,CAAC;AACzC,OAAO,EACH,kCAAkC,EAClC,iCAAiC,EACjC,kCAAkC,EACrC,MAAM,wCAAwC,CAAC;AAChD,OAAO,EAAE,KAAK,EAAE,MAAM,yBAAyB,CAAC;AAChD,OAAO,EAAE,aAAa,EAAE,MAAM,0BAA0B,CAAC;AACzD,OAAO,EAAE,gBAAgB,EAAE,MAAM,sCAAsC,CAAC;AAExE,MAAM,CAAC,MAAM,MAAM,GAAG,GAAG,CAAA;MACnB,OAAO,CAAC,MAAM,CAAC;;;;4BAIO,0BAA0B;;sBAEhC,mBAAmB;;iBAExB,gBAAgB;kBACf,iBAAiB;sBACb,oBAAoB;;;;;;;;;;;;;eAa3B,YAAY;;;;UAIjB,gBAAgB;;;;gBAIV,cAAc;iBACb,mBAAmB;;;;;;;gBAOpB,YAAY;iBACX,iBAAiB;;;;;;gBAMlB,QAAQ;iBACP,aAAa;;;eAGf,eAAe;;UAEpB;AACE;;;;;GAKG;AACH,EACJ;;;;;;qCAM6B,qBAAqB;;;;;eAK3C,eAAe;;;;;;;;;;;;CAY7B,CAAC,aAAa;AACX;;;GAGG;AACH,aAAa,CACT,KAAK,CAAC,KAAK,EACX,GAAG,CAAA;;8BAEmB,kCAAkC;;SAEvD,CACJ,EACD,aAAa,CACT,KAAK,CAAC,IAAI,EACV,GAAG,CAAA;;8BAEmB,iCAAiC;;SAEtD,CACJ,EACD,aAAa,CACT,KAAK,CAAC,KAAK,EACX,GAAG,CAAA;;8BAEmB,kCAAkC;;SAEvD,CACJ,CACJ,CAAC","sourcesContent":["import { css } from '@microsoft/fast-element';\nimport { display } from '@microsoft/fast-foundation';\n\nimport {\n applicationBackgroundColor,\n standardPadding,\n actionRgbPartialColor,\n bodyFont,\n bodyFontColor,\n titlePlus1Font,\n titlePlus1FontColor,\n smallPadding,\n subtitleFont,\n subtitleFontColor,\n elevation3BoxShadow,\n dialogSmallWidth,\n dialogSmallHeight,\n dialogSmallMaxHeight\n} from '../theme-provider/design-tokens';\nimport {\n modalBackdropColorThemeColorStatic,\n modalBackdropColorThemeDarkStatic,\n modalBackdropColorThemeLightStatic\n} from '../theme-provider/design-tokens-static';\nimport { Theme } from '../theme-provider/types';\nimport { themeBehavior } from '../utilities/style/theme';\nimport { accessiblyHidden } from '../utilities/style/accessibly-hidden';\n\nexport const styles = css`\n ${display('grid')}\n\n dialog {\n flex-direction: column;\n background-color: ${applicationBackgroundColor};\n border: none;\n box-shadow: ${elevation3BoxShadow};\n padding: 0px;\n width: ${dialogSmallWidth};\n height: ${dialogSmallHeight};\n max-height: ${dialogSmallMaxHeight};\n }\n\n dialog[open] {\n display: flex;\n }\n\n header {\n min-height: 48px;\n padding: 24px 24px 0px 24px;\n flex: none;\n display: flex;\n flex-direction: column;\n gap: ${smallPadding};\n }\n\n :host([header-hidden]) header {\n ${accessiblyHidden}\n }\n\n .title {\n font: ${titlePlus1Font};\n color: ${titlePlus1FontColor};\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n }\n\n .subtitle {\n font: ${subtitleFont};\n color: ${subtitleFontColor};\n }\n\n section {\n flex: auto;\n overflow-y: auto;\n font: ${bodyFont};\n color: ${bodyFontColor};\n display: flex;\n flex-direction: column;\n gap: ${standardPadding};\n\n ${\n /**\n * Use padding on all sides except the top because the padding is within\n * the scrollable area. The whole scrollable area, including the top of\n * the scrollbar, should be 24px away from the header, so use a margin\n * instead of padding for the top.\n */\n ''\n }\n padding: 0px 24px 24px 24px;\n margin-top: 24px;\n }\n\n footer {\n border-top: 2px solid rgba(${actionRgbPartialColor}, 0.1);\n padding: 24px;\n flex: none;\n display: flex;\n justify-content: flex-end;\n gap: ${standardPadding};\n }\n\n footer.empty {\n padding: 0px;\n height: 72px;\n border-top: none;\n }\n\n :host([footer-hidden]) footer {\n display: none;\n }\n`.withBehaviors(\n /*\n * We cannot use the modalBackdropColor token directly because the backdrop\n * element is not a descendant of the nimble-theme-provider element.\n */\n themeBehavior(\n Theme.light,\n css`\n dialog::backdrop {\n background: ${modalBackdropColorThemeLightStatic};\n }\n `\n ),\n themeBehavior(\n Theme.dark,\n css`\n dialog::backdrop {\n background: ${modalBackdropColorThemeDarkStatic};\n }\n `\n ),\n themeBehavior(\n Theme.color,\n css`\n dialog::backdrop {\n background: ${modalBackdropColorThemeColorStatic};\n }\n `\n )\n);\n"]}
1
+ {"version":3,"file":"styles.js","sourceRoot":"","sources":["../../../src/dialog/styles.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,GAAG,EAAE,MAAM,yBAAyB,CAAC;AAC9C,OAAO,EAAE,OAAO,EAAE,MAAM,4BAA4B,CAAC;AAErD,OAAO,EACH,0BAA0B,EAC1B,eAAe,EACf,qBAAqB,EACrB,QAAQ,EACR,aAAa,EACb,cAAc,EACd,mBAAmB,EACnB,YAAY,EACZ,YAAY,EACZ,iBAAiB,EACjB,mBAAmB,EACnB,gBAAgB,EAChB,iBAAiB,EACjB,oBAAoB,EACpB,gBAAgB,EACnB,MAAM,iCAAiC,CAAC;AACzC,OAAO,EACH,kCAAkC,EAClC,iCAAiC,EACjC,kCAAkC,EACrC,MAAM,wCAAwC,CAAC;AAChD,OAAO,EAAE,KAAK,EAAE,MAAM,yBAAyB,CAAC;AAChD,OAAO,EAAE,aAAa,EAAE,MAAM,0BAA0B,CAAC;AACzD,OAAO,EAAE,gBAAgB,EAAE,MAAM,sCAAsC,CAAC;AACxE,OAAO,EAAE,YAAY,EAAE,MAAM,0BAA0B,CAAC;AAExD,MAAM,CAAC,MAAM,MAAM,GAAG,GAAG,CAAA;MACnB,OAAO,CAAC,MAAM,CAAC;;;;4BAIO,0BAA0B;;sBAEhC,mBAAmB;;iBAExB,gBAAgB;kBACf,iBAAiB;sBACb,oBAAoB;;;;;;;YAO9B,YAAY;6BACK,gBAAgB;;;;;;;;;eAS9B,YAAY;;;;UAIjB,gBAAgB;;;;gBAIV,cAAc;iBACb,mBAAmB;;;;;;;gBAOpB,YAAY;iBACX,iBAAiB;;;;;;gBAMlB,QAAQ;iBACP,aAAa;;;eAGf,eAAe;;UAEpB;AACE;;;;;GAKG;AACH,EACJ;;;;;;qCAM6B,qBAAqB;;;;;eAK3C,eAAe;;;;;;;;;;;;CAY7B,CAAC,aAAa;AACX;;;GAGG;AACH,aAAa,CACT,KAAK,CAAC,KAAK,EACX,GAAG,CAAA;;8BAEmB,kCAAkC;;SAEvD,CACJ,EACD,aAAa,CACT,KAAK,CAAC,IAAI,EACV,GAAG,CAAA;;8BAEmB,iCAAiC;;SAEtD,CACJ,EACD,aAAa,CACT,KAAK,CAAC,KAAK,EACX,GAAG,CAAA;;8BAEmB,kCAAkC;;SAEvD,CACJ,CACJ,CAAC","sourcesContent":["import { css } from '@microsoft/fast-element';\nimport { display } from '@microsoft/fast-foundation';\n\nimport {\n applicationBackgroundColor,\n standardPadding,\n actionRgbPartialColor,\n bodyFont,\n bodyFontColor,\n titlePlus1Font,\n titlePlus1FontColor,\n smallPadding,\n subtitleFont,\n subtitleFontColor,\n elevation3BoxShadow,\n dialogSmallWidth,\n dialogSmallHeight,\n dialogSmallMaxHeight,\n borderHoverColor\n} from '../theme-provider/design-tokens';\nimport {\n modalBackdropColorThemeColorStatic,\n modalBackdropColorThemeDarkStatic,\n modalBackdropColorThemeLightStatic\n} from '../theme-provider/design-tokens-static';\nimport { Theme } from '../theme-provider/types';\nimport { themeBehavior } from '../utilities/style/theme';\nimport { accessiblyHidden } from '../utilities/style/accessibly-hidden';\nimport { focusVisible } from '../utilities/style/focus';\n\nexport const styles = css`\n ${display('grid')}\n\n dialog {\n flex-direction: column;\n background-color: ${applicationBackgroundColor};\n border: none;\n box-shadow: ${elevation3BoxShadow};\n padding: 0px;\n width: ${dialogSmallWidth};\n height: ${dialogSmallHeight};\n max-height: ${dialogSmallMaxHeight};\n }\n\n dialog[open] {\n display: flex;\n }\n\n dialog${focusVisible} {\n outline: 2px solid ${borderHoverColor};\n }\n\n header {\n min-height: 48px;\n padding: 24px 24px 0px 24px;\n flex: none;\n display: flex;\n flex-direction: column;\n gap: ${smallPadding};\n }\n\n :host([header-hidden]) header {\n ${accessiblyHidden}\n }\n\n .title {\n font: ${titlePlus1Font};\n color: ${titlePlus1FontColor};\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n }\n\n .subtitle {\n font: ${subtitleFont};\n color: ${subtitleFontColor};\n }\n\n section {\n flex: auto;\n overflow-y: auto;\n font: ${bodyFont};\n color: ${bodyFontColor};\n display: flex;\n flex-direction: column;\n gap: ${standardPadding};\n\n ${\n /**\n * Use padding on all sides except the top because the padding is within\n * the scrollable area. The whole scrollable area, including the top of\n * the scrollbar, should be 24px away from the header, so use a margin\n * instead of padding for the top.\n */\n ''\n }\n padding: 0px 24px 24px 24px;\n margin-top: 24px;\n }\n\n footer {\n border-top: 2px solid rgba(${actionRgbPartialColor}, 0.1);\n padding: 24px;\n flex: none;\n display: flex;\n justify-content: flex-end;\n gap: ${standardPadding};\n }\n\n footer.empty {\n padding: 0px;\n height: 72px;\n border-top: none;\n }\n\n :host([footer-hidden]) footer {\n display: none;\n }\n`.withBehaviors(\n /*\n * We cannot use the modalBackdropColor token directly because the backdrop\n * element is not a descendant of the nimble-theme-provider element.\n */\n themeBehavior(\n Theme.light,\n css`\n dialog::backdrop {\n background: ${modalBackdropColorThemeLightStatic};\n }\n `\n ),\n themeBehavior(\n Theme.dark,\n css`\n dialog::backdrop {\n background: ${modalBackdropColorThemeDarkStatic};\n }\n `\n ),\n themeBehavior(\n Theme.color,\n css`\n dialog::backdrop {\n background: ${modalBackdropColorThemeColorStatic};\n }\n `\n )\n);\n"]}
@@ -6,6 +6,7 @@ export const template = html `
6
6
  role="dialog"
7
7
  part="control"
8
8
  @cancel="${(x, c) => x.cancelHandler(c.event)}"
9
+ @close="${x => x.closeHandler()}"
9
10
  aria-labelledby="header"
10
11
  >
11
12
  <header id="header">
@@ -1 +1 @@
1
- {"version":3,"file":"template.js","sourceRoot":"","sources":["../../../src/dialog/template.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,IAAI,EAAE,GAAG,EAAE,OAAO,EAAE,MAAM,yBAAyB,CAAC;AAG7D,MAAM,CAAC,MAAM,QAAQ,GAAG,IAAI,CAAQ;;;cAGtB,GAAG,CAAC,eAAe,CAAC;;;uBAGX,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,aAAa,CAAC,CAAC,CAAC,KAAK,CAAC;;;;;;;;;;;;;;6BAc5B,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,aAAa,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,EAAE,CAAC;;;sBAG5C,OAAO,CAAC,EAAE,QAAQ,EAAE,uBAAuB,EAAE,CAAC;;;;;CAKnE,CAAC","sourcesContent":["import { html, ref, slotted } from '@microsoft/fast-element';\nimport type { Dialog } from '.';\n\nexport const template = html<Dialog>`\n <template>\n <dialog\n ${ref('dialogElement')}\n role=\"dialog\"\n part=\"control\"\n @cancel=\"${(x, c) => x.cancelHandler(c.event)}\"\n aria-labelledby=\"header\"\n >\n <header id=\"header\">\n <div class=\"title\">\n <slot name=\"title\"></slot>\n </div>\n <div class=\"subtitle\">\n <slot name=\"subtitle\"></slot>\n </div>\n </header>\n <section>\n <slot></slot>\n </section>\n <footer class=\"${x => (x.footerIsEmpty ? 'empty' : '')}\">\n <slot\n name=\"footer\"\n ${slotted({ property: 'slottedFooterElements' })}\n ></slot>\n </footer>\n </dialog>\n </template>\n`;\n"]}
1
+ {"version":3,"file":"template.js","sourceRoot":"","sources":["../../../src/dialog/template.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,IAAI,EAAE,GAAG,EAAE,OAAO,EAAE,MAAM,yBAAyB,CAAC;AAG7D,MAAM,CAAC,MAAM,QAAQ,GAAG,IAAI,CAAQ;;;cAGtB,GAAG,CAAC,eAAe,CAAC;;;uBAGX,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,aAAa,CAAC,CAAC,CAAC,KAAK,CAAC;sBACnC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,YAAY,EAAE;;;;;;;;;;;;;;6BAcd,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,aAAa,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,EAAE,CAAC;;;sBAG5C,OAAO,CAAC,EAAE,QAAQ,EAAE,uBAAuB,EAAE,CAAC;;;;;CAKnE,CAAC","sourcesContent":["import { html, ref, slotted } from '@microsoft/fast-element';\nimport type { Dialog } from '.';\n\nexport const template = html<Dialog>`\n <template>\n <dialog\n ${ref('dialogElement')}\n role=\"dialog\"\n part=\"control\"\n @cancel=\"${(x, c) => x.cancelHandler(c.event)}\"\n @close=\"${x => x.closeHandler()}\"\n aria-labelledby=\"header\"\n >\n <header id=\"header\">\n <div class=\"title\">\n <slot name=\"title\"></slot>\n </div>\n <div class=\"subtitle\">\n <slot name=\"subtitle\"></slot>\n </div>\n </header>\n <section>\n <slot></slot>\n </section>\n <footer class=\"${x => (x.footerIsEmpty ? 'empty' : '')}\">\n <slot\n name=\"footer\"\n ${slotted({ property: 'slottedFooterElements' })}\n ></slot>\n </footer>\n </dialog>\n </template>\n`;\n"]}
@@ -40,6 +40,11 @@ export declare class Drawer<CloseReason = void> extends FoundationElement {
40
40
  * @internal
41
41
  */
42
42
  cancelHandler(event: Event): boolean;
43
+ /**
44
+ * @internal
45
+ */
46
+ closeHandler(): void;
47
+ private doResolveShow;
43
48
  private readonly animationEndHandlerFunction;
44
49
  private openDialog;
45
50
  private closeDialog;
@@ -65,6 +65,26 @@ export class Drawer extends FoundationElement {
65
65
  }
66
66
  return true;
67
67
  }
68
+ /**
69
+ * @internal
70
+ */
71
+ closeHandler() {
72
+ if (this.resolveShow) {
73
+ // If
74
+ // - the browser implements dialogs with the CloseWatcher API, and
75
+ // - the user presses ESC without first interacting with the drawer (e.g. clicking, scrolling),
76
+ // the cancel event is not fired, but the close event still is, and the drawer just closes.
77
+ // The animation is never started, so there is no animation end listener to clean up.
78
+ this.doResolveShow(UserDismissed);
79
+ }
80
+ }
81
+ doResolveShow(reason) {
82
+ if (!this.resolveShow) {
83
+ throw new Error('Do not call doResolveShow unless there is a promise to resolve');
84
+ }
85
+ this.resolveShow(reason);
86
+ this.resolveShow = undefined;
87
+ }
68
88
  openDialog() {
69
89
  this.dialog.showModal();
70
90
  this.triggerAnimation();
@@ -87,8 +107,7 @@ export class Drawer extends FoundationElement {
87
107
  this.dialog.classList.remove('closing');
88
108
  this.dialog.close();
89
109
  this.closing = false;
90
- this.resolveShow(this.closeReason);
91
- this.resolveShow = undefined;
110
+ this.doResolveShow(this.closeReason);
92
111
  }
93
112
  }
94
113
  }
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/drawer/index.ts"],"names":[],"mappings":";AAAA,OAAO,EAAE,IAAI,EAAE,MAAM,yBAAyB,CAAC;AAC/C,OAAO,EACH,WAAW,EACX,6BAA6B,EAC7B,YAAY,EACZ,iBAAiB,EACpB,MAAM,4BAA4B,CAAC;AACpC,OAAO,EAAE,iBAAiB,EAAE,MAAM,+BAA+B,CAAC;AAElE,OAAO,EAAE,aAAa,EAAE,MAAM,0BAA0B,CAAC;AACzD,OAAO,EAAE,MAAM,EAAE,MAAM,UAAU,CAAC;AAClC,OAAO,EAAE,QAAQ,EAAE,MAAM,YAAY,CAAC;AACtC,OAAO,EAAE,cAAc,EAAE,MAAM,SAAS,CAAC;AAEzC,OAAO,EAAE,aAAa,EAAE,CAAC;AAQzB;;;GAGG;AACH,mEAAmE;AACnE,MAAM,OAAO,MAA2B,SAAQ,iBAAiB;IAAjE;;QAMW,aAAQ,GAAmB,cAAc,CAAC,KAAK,CAAC;QAGhD,mBAAc,GAAG,KAAK,CAAC;QAGtB,YAAO,GAAG,KAAK,CAAC;QAuDP,gCAA2B,GAAG,GAAS,EAAE,CAAC,IAAI,CAAC,mBAAmB,EAAE,CAAC;IAsC1F,CAAC;IAxFG;;OAEG;IACH,IAAW,IAAI;QACX,OAAO,IAAI,CAAC,WAAW,KAAK,SAAS,CAAC;IAC1C,CAAC;IAED;;;;;OAKG;IACI,KAAK,CAAC,IAAI;QACb,IAAI,IAAI,CAAC,IAAI,EAAE;YACX,MAAM,IAAI,KAAK,CAAC,wBAAwB,CAAC,CAAC;SAC7C;QACD,IAAI,CAAC,UAAU,EAAE,CAAC;QAClB,OAAO,IAAI,OAAO,CAAC,CAAC,OAAO,EAAE,OAAO,EAAE,EAAE;YACpC,IAAI,CAAC,WAAW,GAAG,OAAO,CAAC;QAC/B,CAAC,CAAC,CAAC;IACP,CAAC;IAED;;;OAGG;IACI,KAAK,CAAC,MAAmB;QAC5B,IAAI,CAAC,IAAI,CAAC,IAAI,IAAI,IAAI,CAAC,OAAO,EAAE;YAC5B,MAAM,IAAI,KAAK,CAAC,uCAAuC,CAAC,CAAC;SAC5D;QACD,IAAI,CAAC,WAAW,GAAG,MAAM,CAAC;QAC1B,IAAI,CAAC,WAAW,EAAE,CAAC;IACvB,CAAC;IAED;;OAEG;IACI,aAAa,CAAC,KAAY;QAC7B,mFAAmF;QACnF,kEAAkE;QAClE,KAAK,CAAC,cAAc,EAAE,CAAC;QAEvB,IAAI,CAAC,IAAI,CAAC,cAAc,EAAE;YACtB,IAAI,CAAC,WAAW,GAAG,aAAa,CAAC;YACjC,IAAI,CAAC,WAAW,EAAE,CAAC;SACtB;QACD,OAAO,IAAI,CAAC;IAChB,CAAC;IAIO,UAAU;QACd,IAAI,CAAC,MAAM,CAAC,SAAS,EAAE,CAAC;QACxB,IAAI,CAAC,gBAAgB,EAAE,CAAC;IAC5B,CAAC;IAEO,WAAW;QACf,IAAI,CAAC,OAAO,GAAG,IAAI,CAAC;QACpB,IAAI,CAAC,gBAAgB,EAAE,CAAC;IAC5B,CAAC;IAEO,gBAAgB;QACpB,IAAI,CAAC,MAAM,CAAC,SAAS,CAAC,GAAG,CAAC,WAAW,CAAC,CAAC;QACvC,IAAI,IAAI,CAAC,OAAO,EAAE;YACd,IAAI,CAAC,MAAM,CAAC,SAAS,CAAC,GAAG,CAAC,SAAS,CAAC,CAAC;SACxC;QAED,IAAI,CAAC,MAAM,CAAC,gBAAgB,CACxB,iBAAiB,EACjB,IAAI,CAAC,2BAA2B,CACnC,CAAC;IACN,CAAC;IAEO,mBAAmB;QACvB,IAAI,CAAC,MAAM,CAAC,mBAAmB,CAC3B,iBAAiB,EACjB,IAAI,CAAC,2BAA2B,CACnC,CAAC;QACF,IAAI,CAAC,MAAM,CAAC,SAAS,CAAC,MAAM,CAAC,WAAW,CAAC,CAAC;QAC1C,IAAI,IAAI,CAAC,OAAO,EAAE;YACd,IAAI,CAAC,MAAM,CAAC,SAAS,CAAC,MAAM,CAAC,SAAS,CAAC,CAAC;YACxC,IAAI,CAAC,MAAM,CAAC,KAAK,EAAE,CAAC;YACpB,IAAI,CAAC,OAAO,GAAG,KAAK,CAAC;YACrB,IAAI,CAAC,WAAY,CAAC,IAAI,CAAC,WAAW,CAAC,CAAC;YACpC,IAAI,CAAC,WAAW,GAAG,SAAS,CAAC;SAChC;IACL,CAAC;;AAvGD,uDAAuD;AACvD,gEAAgE;AACzC,oBAAa,GAAG,aAAa,CAAC;AAGrD;IADC,IAAI;wCACkD;AAGvD;IADC,IAAI,CAAC,EAAE,SAAS,EAAE,iBAAiB,EAAE,IAAI,EAAE,SAAS,EAAE,CAAC;8CAC1B;AAoGlC,WAAW,CAAC,MAAM,EAAE,6BAA6B,CAAC,CAAC;AAEnD,MAAM,YAAY,GAAG,MAAM,CAAC,OAAO,CAAC;IAChC,QAAQ,EAAE,QAAQ;IAClB,QAAQ;IACR,MAAM;CACT,CAAC,CAAC;AACH,YAAY,CAAC,WAAW,EAAE,CAAC,UAAU,CAAC,QAAQ,CAAC,CAAC,QAAQ,CAAC,YAAY,EAAE,CAAC,CAAC;AACzE,MAAM,CAAC,MAAM,SAAS,GAAG,eAAe,CAAC","sourcesContent":["import { attr } from '@microsoft/fast-element';\nimport {\n applyMixins,\n ARIAGlobalStatesAndProperties,\n DesignSystem,\n FoundationElement\n} from '@microsoft/fast-foundation';\nimport { eventAnimationEnd } from '@microsoft/fast-web-utilities';\nimport type { ExtendedDialog } from '../dialog';\nimport { UserDismissed } from '../patterns/dialog/types';\nimport { styles } from './styles';\nimport { template } from './template';\nimport { DrawerLocation } from './types';\n\nexport { UserDismissed };\n\ndeclare global {\n interface HTMLElementTagNameMap {\n 'nimble-drawer': Drawer;\n }\n}\n\n/**\n * Drawer control. Shows content in a panel on the left / right side of the screen,\n * which animates to be visible with a slide-in / slide-out animation.\n */\n// eslint-disable-next-line @typescript-eslint/no-invalid-void-type\nexport class Drawer<CloseReason = void> extends FoundationElement {\n // We want the member to match the name of the constant\n // eslint-disable-next-line @typescript-eslint/naming-convention\n public static readonly UserDismissed = UserDismissed;\n\n @attr\n public location: DrawerLocation = DrawerLocation.right;\n\n @attr({ attribute: 'prevent-dismiss', mode: 'boolean' })\n public preventDismiss = false;\n\n public dialog!: ExtendedDialog;\n private closing = false;\n\n private resolveShow?: (reason: CloseReason | UserDismissed) => void;\n private closeReason!: CloseReason | UserDismissed;\n\n /**\n * True if the drawer is open, opening, or closing. Otherwise, false.\n */\n public get open(): boolean {\n return this.resolveShow !== undefined;\n }\n\n /**\n * Opens the drawer\n * @returns Promise that is resolved when the drawer finishes closing. The value of the resolved\n * Promise is the reason value passed to the close() method, or UserDismissed if the drawer was\n * closed via the ESC key.\n */\n public async show(): Promise<CloseReason | UserDismissed> {\n if (this.open) {\n throw new Error('Drawer is already open');\n }\n this.openDialog();\n return new Promise((resolve, _reject) => {\n this.resolveShow = resolve;\n });\n }\n\n /**\n * Closes the drawer\n * @param reason An optional value indicating how/why the drawer was closed.\n */\n public close(reason: CloseReason): void {\n if (!this.open || this.closing) {\n throw new Error('Drawer is not open or already closing');\n }\n this.closeReason = reason;\n this.closeDialog();\n }\n\n /**\n * @internal\n */\n public cancelHandler(event: Event): boolean {\n // Allowing the dialog to close itself bypasses the drawer's animation logic, so we\n // should close the drawer ourselves when preventDismiss is false.\n event.preventDefault();\n\n if (!this.preventDismiss) {\n this.closeReason = UserDismissed;\n this.closeDialog();\n }\n return true;\n }\n\n private readonly animationEndHandlerFunction = (): void => this.animationEndHandler();\n\n private openDialog(): void {\n this.dialog.showModal();\n this.triggerAnimation();\n }\n\n private closeDialog(): void {\n this.closing = true;\n this.triggerAnimation();\n }\n\n private triggerAnimation(): void {\n this.dialog.classList.add('animating');\n if (this.closing) {\n this.dialog.classList.add('closing');\n }\n\n this.dialog.addEventListener(\n eventAnimationEnd,\n this.animationEndHandlerFunction\n );\n }\n\n private animationEndHandler(): void {\n this.dialog.removeEventListener(\n eventAnimationEnd,\n this.animationEndHandlerFunction\n );\n this.dialog.classList.remove('animating');\n if (this.closing) {\n this.dialog.classList.remove('closing');\n this.dialog.close();\n this.closing = false;\n this.resolveShow!(this.closeReason);\n this.resolveShow = undefined;\n }\n }\n}\n\n// eslint-disable-next-line @typescript-eslint/no-empty-interface\nexport interface Drawer extends ARIAGlobalStatesAndProperties {}\napplyMixins(Drawer, ARIAGlobalStatesAndProperties);\n\nconst nimbleDrawer = Drawer.compose({\n baseName: 'drawer',\n template,\n styles\n});\nDesignSystem.getOrCreate().withPrefix('nimble').register(nimbleDrawer());\nexport const drawerTag = 'nimble-drawer';\n"]}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/drawer/index.ts"],"names":[],"mappings":"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","sourcesContent":["import { attr } from '@microsoft/fast-element';\nimport {\n applyMixins,\n ARIAGlobalStatesAndProperties,\n DesignSystem,\n FoundationElement\n} from '@microsoft/fast-foundation';\nimport { eventAnimationEnd } from '@microsoft/fast-web-utilities';\nimport type { ExtendedDialog } from '../dialog';\nimport { UserDismissed } from '../patterns/dialog/types';\nimport { styles } from './styles';\nimport { template } from './template';\nimport { DrawerLocation } from './types';\n\nexport { UserDismissed };\n\ndeclare global {\n interface HTMLElementTagNameMap {\n 'nimble-drawer': Drawer;\n }\n}\n\n/**\n * Drawer control. Shows content in a panel on the left / right side of the screen,\n * which animates to be visible with a slide-in / slide-out animation.\n */\n// eslint-disable-next-line @typescript-eslint/no-invalid-void-type\nexport class Drawer<CloseReason = void> extends FoundationElement {\n // We want the member to match the name of the constant\n // eslint-disable-next-line @typescript-eslint/naming-convention\n public static readonly UserDismissed = UserDismissed;\n\n @attr\n public location: DrawerLocation = DrawerLocation.right;\n\n @attr({ attribute: 'prevent-dismiss', mode: 'boolean' })\n public preventDismiss = false;\n\n public dialog!: ExtendedDialog;\n private closing = false;\n\n private resolveShow?: (reason: CloseReason | UserDismissed) => void;\n private closeReason!: CloseReason | UserDismissed;\n\n /**\n * True if the drawer is open, opening, or closing. Otherwise, false.\n */\n public get open(): boolean {\n return this.resolveShow !== undefined;\n }\n\n /**\n * Opens the drawer\n * @returns Promise that is resolved when the drawer finishes closing. The value of the resolved\n * Promise is the reason value passed to the close() method, or UserDismissed if the drawer was\n * closed via the ESC key.\n */\n public async show(): Promise<CloseReason | UserDismissed> {\n if (this.open) {\n throw new Error('Drawer is already open');\n }\n this.openDialog();\n return new Promise((resolve, _reject) => {\n this.resolveShow = resolve;\n });\n }\n\n /**\n * Closes the drawer\n * @param reason An optional value indicating how/why the drawer was closed.\n */\n public close(reason: CloseReason): void {\n if (!this.open || this.closing) {\n throw new Error('Drawer is not open or already closing');\n }\n this.closeReason = reason;\n this.closeDialog();\n }\n\n /**\n * @internal\n */\n public cancelHandler(event: Event): boolean {\n // Allowing the dialog to close itself bypasses the drawer's animation logic, so we\n // should close the drawer ourselves when preventDismiss is false.\n event.preventDefault();\n\n if (!this.preventDismiss) {\n this.closeReason = UserDismissed;\n this.closeDialog();\n }\n return true;\n }\n\n /**\n * @internal\n */\n public closeHandler(): void {\n if (this.resolveShow) {\n // If\n // - the browser implements dialogs with the CloseWatcher API, and\n // - the user presses ESC without first interacting with the drawer (e.g. clicking, scrolling),\n // the cancel event is not fired, but the close event still is, and the drawer just closes.\n // The animation is never started, so there is no animation end listener to clean up.\n this.doResolveShow(UserDismissed);\n }\n }\n\n private doResolveShow(reason: CloseReason | UserDismissed): void {\n if (!this.resolveShow) {\n throw new Error(\n 'Do not call doResolveShow unless there is a promise to resolve'\n );\n }\n this.resolveShow(reason);\n this.resolveShow = undefined;\n }\n\n private readonly animationEndHandlerFunction = (): void => this.animationEndHandler();\n\n private openDialog(): void {\n this.dialog.showModal();\n this.triggerAnimation();\n }\n\n private closeDialog(): void {\n this.closing = true;\n this.triggerAnimation();\n }\n\n private triggerAnimation(): void {\n this.dialog.classList.add('animating');\n if (this.closing) {\n this.dialog.classList.add('closing');\n }\n\n this.dialog.addEventListener(\n eventAnimationEnd,\n this.animationEndHandlerFunction\n );\n }\n\n private animationEndHandler(): void {\n this.dialog.removeEventListener(\n eventAnimationEnd,\n this.animationEndHandlerFunction\n );\n this.dialog.classList.remove('animating');\n if (this.closing) {\n this.dialog.classList.remove('closing');\n this.dialog.close();\n this.closing = false;\n this.doResolveShow(this.closeReason);\n }\n }\n}\n\n// eslint-disable-next-line @typescript-eslint/no-empty-interface\nexport interface Drawer extends ARIAGlobalStatesAndProperties {}\napplyMixins(Drawer, ARIAGlobalStatesAndProperties);\n\nconst nimbleDrawer = Drawer.compose({\n baseName: 'drawer',\n template,\n styles\n});\nDesignSystem.getOrCreate().withPrefix('nimble').register(nimbleDrawer());\nexport const drawerTag = 'nimble-drawer';\n"]}
@@ -4,6 +4,7 @@ export const template = html `
4
4
  ${ref('dialog')}
5
5
  aria-label="${x => x.ariaLabel}"
6
6
  @cancel="${(x, c) => x.cancelHandler(c.event)}"
7
+ @close="${x => x.closeHandler()}"
7
8
  >
8
9
  <div class="dialog-contents">
9
10
  <slot></slot>
@@ -1 +1 @@
1
- {"version":3,"file":"template.js","sourceRoot":"","sources":["../../../src/drawer/template.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,IAAI,EAAE,GAAG,EAAE,MAAM,yBAAyB,CAAC;AAGpD,MAAM,CAAC,MAAM,QAAQ,GAAG,IAAI,CAAQ;;UAE1B,GAAG,CAAC,QAAQ,CAAC;sBACD,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,SAAS;mBACnB,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,aAAa,CAAC,CAAC,CAAC,KAAK,CAAC;;;;;;CAMpD,CAAC","sourcesContent":["import { html, ref } from '@microsoft/fast-element';\nimport type { Drawer } from '.';\n\nexport const template = html<Drawer>`\n <dialog\n ${ref('dialog')}\n aria-label=\"${x => x.ariaLabel}\"\n @cancel=\"${(x, c) => x.cancelHandler(c.event)}\"\n >\n <div class=\"dialog-contents\">\n <slot></slot>\n </div>\n </dialog>\n`;\n"]}
1
+ {"version":3,"file":"template.js","sourceRoot":"","sources":["../../../src/drawer/template.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,IAAI,EAAE,GAAG,EAAE,MAAM,yBAAyB,CAAC;AAGpD,MAAM,CAAC,MAAM,QAAQ,GAAG,IAAI,CAAQ;;UAE1B,GAAG,CAAC,QAAQ,CAAC;sBACD,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,SAAS;mBACnB,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,aAAa,CAAC,CAAC,CAAC,KAAK,CAAC;kBACnC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,YAAY,EAAE;;;;;;CAMtC,CAAC","sourcesContent":["import { html, ref } from '@microsoft/fast-element';\nimport type { Drawer } from '.';\n\nexport const template = html<Drawer>`\n <dialog\n ${ref('dialog')}\n aria-label=\"${x => x.ariaLabel}\"\n @cancel=\"${(x, c) => x.cancelHandler(c.event)}\"\n @close=\"${x => x.closeHandler()}\"\n >\n <div class=\"dialog-contents\">\n <slot></slot>\n </div>\n </dialog>\n`;\n"]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ni/nimble-components",
3
- "version": "21.6.2",
3
+ "version": "21.6.3",
4
4
  "description": "Styled web components for the NI Nimble Design System",
5
5
  "scripts": {
6
6
  "build": "npm run generate-icons && npm run build-components && npm run bundle-components && npm run generate-scss && npm run build-storybook",