From 7f9af9e7d13c4aadc6a8b6a1f48d46c7bd64c745 Mon Sep 17 00:00:00 2001 From: Brian Brady Date: Fri, 3 Mar 2023 10:45:00 -0800 Subject: [PATCH 01/45] radio init --- .../web-components/src/radio-group/define.ts | 4 + .../web-components/src/radio-group/index.ts | 4 + .../src/radio-group/radio-group.definition.ts | 18 +++ .../src/radio-group/radio-group.styles.ts | 31 +++++ .../src/radio-group/radio-group.template.ts | 5 + .../src/radio-group/radio-group.ts | 8 ++ packages/web-components/src/radio/define.ts | 4 + packages/web-components/src/radio/index.ts | 5 + .../src/radio/radio.definition.ts | 18 +++ .../web-components/src/radio/radio.stories.ts | 24 ++++ .../web-components/src/radio/radio.styles.ts | 118 ++++++++++++++++++ .../src/radio/radio.template.ts | 7 ++ packages/web-components/src/radio/radio.ts | 8 ++ 13 files changed, 254 insertions(+) create mode 100644 packages/web-components/src/radio-group/define.ts create mode 100644 packages/web-components/src/radio-group/index.ts create mode 100644 packages/web-components/src/radio-group/radio-group.definition.ts create mode 100644 packages/web-components/src/radio-group/radio-group.styles.ts create mode 100644 packages/web-components/src/radio-group/radio-group.template.ts create mode 100644 packages/web-components/src/radio-group/radio-group.ts create mode 100644 packages/web-components/src/radio/define.ts create mode 100644 packages/web-components/src/radio/index.ts create mode 100644 packages/web-components/src/radio/radio.definition.ts create mode 100644 packages/web-components/src/radio/radio.stories.ts create mode 100644 packages/web-components/src/radio/radio.styles.ts create mode 100644 packages/web-components/src/radio/radio.template.ts create mode 100644 packages/web-components/src/radio/radio.ts diff --git a/packages/web-components/src/radio-group/define.ts b/packages/web-components/src/radio-group/define.ts new file mode 100644 index 00000000000000..2da64783f83419 --- /dev/null +++ b/packages/web-components/src/radio-group/define.ts @@ -0,0 +1,4 @@ +import { FluentDesignSystem } from '../fluent-design-system.js'; +import { definition } from './radio-group.definition.js'; + +definition.define(FluentDesignSystem.registry); diff --git a/packages/web-components/src/radio-group/index.ts b/packages/web-components/src/radio-group/index.ts new file mode 100644 index 00000000000000..967f498a393fbf --- /dev/null +++ b/packages/web-components/src/radio-group/index.ts @@ -0,0 +1,4 @@ +export * from './radio-group.js'; +export { definition as RadioGroupDefinition } from './radio-group.definition.js'; +export { styles as RadioGroupStyles } from './radio-group.styles.js'; +export { template as RadioGroupTemplate } from './radio-group.template.js'; diff --git a/packages/web-components/src/radio-group/radio-group.definition.ts b/packages/web-components/src/radio-group/radio-group.definition.ts new file mode 100644 index 00000000000000..0e3f17541c84b8 --- /dev/null +++ b/packages/web-components/src/radio-group/radio-group.definition.ts @@ -0,0 +1,18 @@ +import { FluentDesignSystem } from '../fluent-design-system.js'; +import { RadioGroup } from './radio-group.js'; +import { styles } from './radio-group.styles.js'; +import { template } from './radio-group.template.js'; + +/** + * The Fluent RadioGroup Element. + * + * + * @public + * @remarks + * HTML Element: \ + */ +export const definition = RadioGroup.compose({ + name: `${FluentDesignSystem.prefix}-radio-group`, + template, + styles, +}); diff --git a/packages/web-components/src/radio-group/radio-group.styles.ts b/packages/web-components/src/radio-group/radio-group.styles.ts new file mode 100644 index 00000000000000..d15d9061179e6d --- /dev/null +++ b/packages/web-components/src/radio-group/radio-group.styles.ts @@ -0,0 +1,31 @@ +import { css } from '@microsoft/fast-element'; +import { display } from '@microsoft/fast-foundation'; +import {} from '../theme/design-tokens.js'; + +/** Radio styles + * @public + */ +export const styles = css` + :host([hidden]) { + display: none; + } + :host { + align-items: flex-start; + display: flex; + flex-direction: column; + margin: 2px 0; + } + .positioning-region { + display: flex; + flex-wrap: wrap; + } + :host([orientation='vertical']) .positioning-region { + flex-direction: column; + } + :host([orientation='horizontal']) .positioning-region { + flex-direction: row; + } + :host([disabled]) { + opacity: 0.5; + } +`; diff --git a/packages/web-components/src/radio-group/radio-group.template.ts b/packages/web-components/src/radio-group/radio-group.template.ts new file mode 100644 index 00000000000000..d13afcb79a5c00 --- /dev/null +++ b/packages/web-components/src/radio-group/radio-group.template.ts @@ -0,0 +1,5 @@ +import type { ElementViewTemplate } from '@microsoft/fast-element'; +import { radioGroupTemplate } from '@microsoft/fast-foundation'; +import type { Radio } from './radio-group.js'; + +export const template: ElementViewTemplate = radioGroupTemplate(); diff --git a/packages/web-components/src/radio-group/radio-group.ts b/packages/web-components/src/radio-group/radio-group.ts new file mode 100644 index 00000000000000..d21a5ad81f0e6f --- /dev/null +++ b/packages/web-components/src/radio-group/radio-group.ts @@ -0,0 +1,8 @@ +import { attr } from '@microsoft/fast-element'; +import { FASTRadioGroup } from '@microsoft/fast-foundation'; + +/** + * The base class used for constructing a fluent-radio-group custom element + * @public + */ +export class RadioGroup extends FASTRadioGroup {} diff --git a/packages/web-components/src/radio/define.ts b/packages/web-components/src/radio/define.ts new file mode 100644 index 00000000000000..66ca2a55ac25be --- /dev/null +++ b/packages/web-components/src/radio/define.ts @@ -0,0 +1,4 @@ +import { FluentDesignSystem } from '../fluent-design-system.js'; +import { definition } from './radio.definition.js'; + +definition.define(FluentDesignSystem.registry); diff --git a/packages/web-components/src/radio/index.ts b/packages/web-components/src/radio/index.ts new file mode 100644 index 00000000000000..dc9ccc345f6885 --- /dev/null +++ b/packages/web-components/src/radio/index.ts @@ -0,0 +1,5 @@ +export * from './radio.js'; +export * from './radio.options.js'; +export { definition as RadioDefinition } from './radio.definition.js'; +export { styles as RadioStyles } from './radio.styles.js'; +export { template as RadioTemplate } from './radio.template.js'; diff --git a/packages/web-components/src/radio/radio.definition.ts b/packages/web-components/src/radio/radio.definition.ts new file mode 100644 index 00000000000000..479c8c1bb37c05 --- /dev/null +++ b/packages/web-components/src/radio/radio.definition.ts @@ -0,0 +1,18 @@ +import { FluentDesignSystem } from '../fluent-design-system.js'; +import { Radio } from './radio.js'; +import { styles } from './radio.styles.js'; +import { template } from './radio.template.js'; + +/** + * The Fluent Radio Element. + * + * + * @public + * @remarks + * HTML Element: \ + */ +export const definition = Radio.compose({ + name: `${FluentDesignSystem.prefix}-radio`, + template, + styles, +}); diff --git a/packages/web-components/src/radio/radio.stories.ts b/packages/web-components/src/radio/radio.stories.ts new file mode 100644 index 00000000000000..7a12c218197cea --- /dev/null +++ b/packages/web-components/src/radio/radio.stories.ts @@ -0,0 +1,24 @@ +import { html } from '@microsoft/fast-element'; +import type { Args, Meta } from '@storybook/html'; +import { renderComponent } from '../helpers.stories.js'; +import type { Radio as FluentRadio } from './radio.js'; +import './define.js'; +import '../radio-group/define.js'; + +type RadioStoryArgs = Args & FluentRadio; +type RadioStoryMeta = Meta; + +const storyTemplate = html` + + Label + Label 2 + +`; + +export default { + title: 'Components/Radio', + args: {}, + argTypes: {}, +} as RadioStoryMeta; + +export const Radio = renderComponent(storyTemplate).bind({}); diff --git a/packages/web-components/src/radio/radio.styles.ts b/packages/web-components/src/radio/radio.styles.ts new file mode 100644 index 00000000000000..750fae32d4f4dc --- /dev/null +++ b/packages/web-components/src/radio/radio.styles.ts @@ -0,0 +1,118 @@ +import { css } from '@microsoft/fast-element'; +import { display } from '@microsoft/fast-foundation'; +import { + colorNeutralForeground3, + colorNeutralStrokeAccessible, + fontFamilyBase, + fontSizeBase300, + fontWeightRegular, + lineHeightBase300, + spacingHorizontalS, + spacingHorizontalXS, + spacingVerticalS, +} from '../theme/design-tokens.js'; + +/** Radio styles + * @public + */ +export const styles = css` + ${display('inline-flex')} + + :host { + align-items: center; + flex-direction: row; + margin: 4px; + outline: none; + position: relative; + user-select: none; + } + .label { + color: ${colorNeutralForeground3}; + cursor: pointer; + padding: ${spacingVerticalS} ${spacingHorizontalS} ${spacingVerticalS} ${spacingHorizontalXS}; + font-family: ${fontFamilyBase}; + font-size: ${fontSizeBase300}; + font-weight: ${fontWeightRegular}; + line-height: ${lineHeightBase300}; + } + .label__hidden { + display: none; + visibility: hidden; + } + .control, + .checked-indicator { + flex-shrink: 0; + } + .control { + position: relative; + display: inline-block; + width: 16px; + height: 16px; + border-radius: 50%; + border: 1px solid ${colorNeutralStrokeAccessible}; + top: 0; + left: 0; + } + .checked-indicator { + opacity: 0; + position: absolute; + top: 50%; + left: 50%; + transform: translate(-50%, -50%); + width: 10px; + height: 10px; + border-radius: 5px; + background-color: #ccc; + } + :host(:not([disabled])) .control:hover { + background: darkblue; + border-color: lightblue; + } + :host(:not([disabled])) .control:active { + background: gray; + border-color: darkgray; + } + :host(:focus-visible) .control { + box-shadow: 0 0 0 2px green, 0 0 0 4px green; + } + :host([aria-checked='true']) .control { + background: purple; + border: 1px solid yellow; + } + :host([aria-checked='true']) .checked-indicator { + opacity: 1; + } + :host([aria-checked='true']:not([disabled])) .control:hover { + background: darkpurple; + border: 1px solid darkyellow; + } + :host([aria-checked='true']:not([disabled])) .control:hover .checked-indicator { + background: green; + fill: lightgreen; + } + :host([aria-checked='true']:not([disabled])) .control:active { + background: orange; + border: 1px solid cyan; + } + :host([aria-checked='true']:not([disabled])) .control:active .checked-indicator { + background: magenta; + fill: pink; + } + :host([aria-checked='true']:focus-visible:not([disabled])) .control { + box-shadow: 0 0 0 2px red, 0 0 0 4px red; + } + :host([disabled]) .label, + :host([readonly]) .label, + :host([readonly]) .control, + :host([disabled]) .control { + cursor: not-allowed; + } + + :host([disabled]) { + opacity: 0.5; + } + + :host([aria-checked='true']) .checked-indicator { + display: block; + } +`; diff --git a/packages/web-components/src/radio/radio.template.ts b/packages/web-components/src/radio/radio.template.ts new file mode 100644 index 00000000000000..ceb729eb8e4426 --- /dev/null +++ b/packages/web-components/src/radio/radio.template.ts @@ -0,0 +1,7 @@ +import { ElementViewTemplate, html } from '@microsoft/fast-element'; +import { radioTemplate } from '@microsoft/fast-foundation'; +import type { Radio } from './radio.js'; + +export const template: ElementViewTemplate = radioTemplate({ + checkedIndicator: html`
`, +}); diff --git a/packages/web-components/src/radio/radio.ts b/packages/web-components/src/radio/radio.ts new file mode 100644 index 00000000000000..de75e9633e6e12 --- /dev/null +++ b/packages/web-components/src/radio/radio.ts @@ -0,0 +1,8 @@ +import { attr } from '@microsoft/fast-element'; +import { FASTRadio } from '@microsoft/fast-foundation'; + +/** + * The base class used for constructing a fluent-radio custom element + * @public + */ +export class Radio extends FASTRadio {} From 70c55e0bbd66fb05df7d79b89fe13b13dcbebc37 Mon Sep 17 00:00:00 2001 From: Brian Brady Date: Fri, 3 Mar 2023 12:34:59 -0800 Subject: [PATCH 02/45] styles radio --- packages/web-components/src/radio/index.ts | 1 - packages/web-components/src/radio/radio.styles.ts | 8 ++++++++ 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/packages/web-components/src/radio/index.ts b/packages/web-components/src/radio/index.ts index dc9ccc345f6885..e1af0f69389a11 100644 --- a/packages/web-components/src/radio/index.ts +++ b/packages/web-components/src/radio/index.ts @@ -1,5 +1,4 @@ export * from './radio.js'; -export * from './radio.options.js'; export { definition as RadioDefinition } from './radio.definition.js'; export { styles as RadioStyles } from './radio.styles.js'; export { template as RadioTemplate } from './radio.template.js'; diff --git a/packages/web-components/src/radio/radio.styles.ts b/packages/web-components/src/radio/radio.styles.ts index 750fae32d4f4dc..7f45a5d3136a48 100644 --- a/packages/web-components/src/radio/radio.styles.ts +++ b/packages/web-components/src/radio/radio.styles.ts @@ -1,8 +1,10 @@ import { css } from '@microsoft/fast-element'; import { display } from '@microsoft/fast-foundation'; import { + colorNeutralForeground2, colorNeutralForeground3, colorNeutralStrokeAccessible, + colorNeutralStrokeAccessibleHover, fontFamilyBase, fontSizeBase300, fontWeightRegular, @@ -35,6 +37,9 @@ export const styles = css` font-weight: ${fontWeightRegular}; line-height: ${lineHeightBase300}; } + :host(:hover) .label { + color: ${colorNeutralForeground2}; + } .label__hidden { display: none; visibility: hidden; @@ -53,6 +58,9 @@ export const styles = css` top: 0; left: 0; } + :host(:hover) .control { + border-color: ${colorNeutralStrokeAccessibleHover}; + } .checked-indicator { opacity: 0; position: absolute; From a72d10fee8de396c3d2c841813ee494cd08a89d0 Mon Sep 17 00:00:00 2001 From: Brian Brady Date: Fri, 3 Mar 2023 15:26:46 -0800 Subject: [PATCH 03/45] reverts branch --- .../web-components/src/radio-group/define.ts | 4 - .../web-components/src/radio-group/index.ts | 4 - .../src/radio-group/radio-group.definition.ts | 18 --- .../src/radio-group/radio-group.styles.ts | 31 ----- .../src/radio-group/radio-group.template.ts | 5 - .../src/radio-group/radio-group.ts | 8 -- packages/web-components/src/radio/define.ts | 4 - packages/web-components/src/radio/index.ts | 4 - .../src/radio/radio.definition.ts | 18 --- .../web-components/src/radio/radio.stories.ts | 24 ---- .../web-components/src/radio/radio.styles.ts | 126 ------------------ .../src/radio/radio.template.ts | 7 - packages/web-components/src/radio/radio.ts | 8 -- 13 files changed, 261 deletions(-) delete mode 100644 packages/web-components/src/radio-group/define.ts delete mode 100644 packages/web-components/src/radio-group/index.ts delete mode 100644 packages/web-components/src/radio-group/radio-group.definition.ts delete mode 100644 packages/web-components/src/radio-group/radio-group.styles.ts delete mode 100644 packages/web-components/src/radio-group/radio-group.template.ts delete mode 100644 packages/web-components/src/radio-group/radio-group.ts delete mode 100644 packages/web-components/src/radio/define.ts delete mode 100644 packages/web-components/src/radio/index.ts delete mode 100644 packages/web-components/src/radio/radio.definition.ts delete mode 100644 packages/web-components/src/radio/radio.stories.ts delete mode 100644 packages/web-components/src/radio/radio.styles.ts delete mode 100644 packages/web-components/src/radio/radio.template.ts delete mode 100644 packages/web-components/src/radio/radio.ts diff --git a/packages/web-components/src/radio-group/define.ts b/packages/web-components/src/radio-group/define.ts deleted file mode 100644 index 2da64783f83419..00000000000000 --- a/packages/web-components/src/radio-group/define.ts +++ /dev/null @@ -1,4 +0,0 @@ -import { FluentDesignSystem } from '../fluent-design-system.js'; -import { definition } from './radio-group.definition.js'; - -definition.define(FluentDesignSystem.registry); diff --git a/packages/web-components/src/radio-group/index.ts b/packages/web-components/src/radio-group/index.ts deleted file mode 100644 index 967f498a393fbf..00000000000000 --- a/packages/web-components/src/radio-group/index.ts +++ /dev/null @@ -1,4 +0,0 @@ -export * from './radio-group.js'; -export { definition as RadioGroupDefinition } from './radio-group.definition.js'; -export { styles as RadioGroupStyles } from './radio-group.styles.js'; -export { template as RadioGroupTemplate } from './radio-group.template.js'; diff --git a/packages/web-components/src/radio-group/radio-group.definition.ts b/packages/web-components/src/radio-group/radio-group.definition.ts deleted file mode 100644 index 0e3f17541c84b8..00000000000000 --- a/packages/web-components/src/radio-group/radio-group.definition.ts +++ /dev/null @@ -1,18 +0,0 @@ -import { FluentDesignSystem } from '../fluent-design-system.js'; -import { RadioGroup } from './radio-group.js'; -import { styles } from './radio-group.styles.js'; -import { template } from './radio-group.template.js'; - -/** - * The Fluent RadioGroup Element. - * - * - * @public - * @remarks - * HTML Element: \ - */ -export const definition = RadioGroup.compose({ - name: `${FluentDesignSystem.prefix}-radio-group`, - template, - styles, -}); diff --git a/packages/web-components/src/radio-group/radio-group.styles.ts b/packages/web-components/src/radio-group/radio-group.styles.ts deleted file mode 100644 index d15d9061179e6d..00000000000000 --- a/packages/web-components/src/radio-group/radio-group.styles.ts +++ /dev/null @@ -1,31 +0,0 @@ -import { css } from '@microsoft/fast-element'; -import { display } from '@microsoft/fast-foundation'; -import {} from '../theme/design-tokens.js'; - -/** Radio styles - * @public - */ -export const styles = css` - :host([hidden]) { - display: none; - } - :host { - align-items: flex-start; - display: flex; - flex-direction: column; - margin: 2px 0; - } - .positioning-region { - display: flex; - flex-wrap: wrap; - } - :host([orientation='vertical']) .positioning-region { - flex-direction: column; - } - :host([orientation='horizontal']) .positioning-region { - flex-direction: row; - } - :host([disabled]) { - opacity: 0.5; - } -`; diff --git a/packages/web-components/src/radio-group/radio-group.template.ts b/packages/web-components/src/radio-group/radio-group.template.ts deleted file mode 100644 index d13afcb79a5c00..00000000000000 --- a/packages/web-components/src/radio-group/radio-group.template.ts +++ /dev/null @@ -1,5 +0,0 @@ -import type { ElementViewTemplate } from '@microsoft/fast-element'; -import { radioGroupTemplate } from '@microsoft/fast-foundation'; -import type { Radio } from './radio-group.js'; - -export const template: ElementViewTemplate = radioGroupTemplate(); diff --git a/packages/web-components/src/radio-group/radio-group.ts b/packages/web-components/src/radio-group/radio-group.ts deleted file mode 100644 index d21a5ad81f0e6f..00000000000000 --- a/packages/web-components/src/radio-group/radio-group.ts +++ /dev/null @@ -1,8 +0,0 @@ -import { attr } from '@microsoft/fast-element'; -import { FASTRadioGroup } from '@microsoft/fast-foundation'; - -/** - * The base class used for constructing a fluent-radio-group custom element - * @public - */ -export class RadioGroup extends FASTRadioGroup {} diff --git a/packages/web-components/src/radio/define.ts b/packages/web-components/src/radio/define.ts deleted file mode 100644 index 66ca2a55ac25be..00000000000000 --- a/packages/web-components/src/radio/define.ts +++ /dev/null @@ -1,4 +0,0 @@ -import { FluentDesignSystem } from '../fluent-design-system.js'; -import { definition } from './radio.definition.js'; - -definition.define(FluentDesignSystem.registry); diff --git a/packages/web-components/src/radio/index.ts b/packages/web-components/src/radio/index.ts deleted file mode 100644 index e1af0f69389a11..00000000000000 --- a/packages/web-components/src/radio/index.ts +++ /dev/null @@ -1,4 +0,0 @@ -export * from './radio.js'; -export { definition as RadioDefinition } from './radio.definition.js'; -export { styles as RadioStyles } from './radio.styles.js'; -export { template as RadioTemplate } from './radio.template.js'; diff --git a/packages/web-components/src/radio/radio.definition.ts b/packages/web-components/src/radio/radio.definition.ts deleted file mode 100644 index 479c8c1bb37c05..00000000000000 --- a/packages/web-components/src/radio/radio.definition.ts +++ /dev/null @@ -1,18 +0,0 @@ -import { FluentDesignSystem } from '../fluent-design-system.js'; -import { Radio } from './radio.js'; -import { styles } from './radio.styles.js'; -import { template } from './radio.template.js'; - -/** - * The Fluent Radio Element. - * - * - * @public - * @remarks - * HTML Element: \ - */ -export const definition = Radio.compose({ - name: `${FluentDesignSystem.prefix}-radio`, - template, - styles, -}); diff --git a/packages/web-components/src/radio/radio.stories.ts b/packages/web-components/src/radio/radio.stories.ts deleted file mode 100644 index 7a12c218197cea..00000000000000 --- a/packages/web-components/src/radio/radio.stories.ts +++ /dev/null @@ -1,24 +0,0 @@ -import { html } from '@microsoft/fast-element'; -import type { Args, Meta } from '@storybook/html'; -import { renderComponent } from '../helpers.stories.js'; -import type { Radio as FluentRadio } from './radio.js'; -import './define.js'; -import '../radio-group/define.js'; - -type RadioStoryArgs = Args & FluentRadio; -type RadioStoryMeta = Meta; - -const storyTemplate = html` - - Label - Label 2 - -`; - -export default { - title: 'Components/Radio', - args: {}, - argTypes: {}, -} as RadioStoryMeta; - -export const Radio = renderComponent(storyTemplate).bind({}); diff --git a/packages/web-components/src/radio/radio.styles.ts b/packages/web-components/src/radio/radio.styles.ts deleted file mode 100644 index 7f45a5d3136a48..00000000000000 --- a/packages/web-components/src/radio/radio.styles.ts +++ /dev/null @@ -1,126 +0,0 @@ -import { css } from '@microsoft/fast-element'; -import { display } from '@microsoft/fast-foundation'; -import { - colorNeutralForeground2, - colorNeutralForeground3, - colorNeutralStrokeAccessible, - colorNeutralStrokeAccessibleHover, - fontFamilyBase, - fontSizeBase300, - fontWeightRegular, - lineHeightBase300, - spacingHorizontalS, - spacingHorizontalXS, - spacingVerticalS, -} from '../theme/design-tokens.js'; - -/** Radio styles - * @public - */ -export const styles = css` - ${display('inline-flex')} - - :host { - align-items: center; - flex-direction: row; - margin: 4px; - outline: none; - position: relative; - user-select: none; - } - .label { - color: ${colorNeutralForeground3}; - cursor: pointer; - padding: ${spacingVerticalS} ${spacingHorizontalS} ${spacingVerticalS} ${spacingHorizontalXS}; - font-family: ${fontFamilyBase}; - font-size: ${fontSizeBase300}; - font-weight: ${fontWeightRegular}; - line-height: ${lineHeightBase300}; - } - :host(:hover) .label { - color: ${colorNeutralForeground2}; - } - .label__hidden { - display: none; - visibility: hidden; - } - .control, - .checked-indicator { - flex-shrink: 0; - } - .control { - position: relative; - display: inline-block; - width: 16px; - height: 16px; - border-radius: 50%; - border: 1px solid ${colorNeutralStrokeAccessible}; - top: 0; - left: 0; - } - :host(:hover) .control { - border-color: ${colorNeutralStrokeAccessibleHover}; - } - .checked-indicator { - opacity: 0; - position: absolute; - top: 50%; - left: 50%; - transform: translate(-50%, -50%); - width: 10px; - height: 10px; - border-radius: 5px; - background-color: #ccc; - } - :host(:not([disabled])) .control:hover { - background: darkblue; - border-color: lightblue; - } - :host(:not([disabled])) .control:active { - background: gray; - border-color: darkgray; - } - :host(:focus-visible) .control { - box-shadow: 0 0 0 2px green, 0 0 0 4px green; - } - :host([aria-checked='true']) .control { - background: purple; - border: 1px solid yellow; - } - :host([aria-checked='true']) .checked-indicator { - opacity: 1; - } - :host([aria-checked='true']:not([disabled])) .control:hover { - background: darkpurple; - border: 1px solid darkyellow; - } - :host([aria-checked='true']:not([disabled])) .control:hover .checked-indicator { - background: green; - fill: lightgreen; - } - :host([aria-checked='true']:not([disabled])) .control:active { - background: orange; - border: 1px solid cyan; - } - :host([aria-checked='true']:not([disabled])) .control:active .checked-indicator { - background: magenta; - fill: pink; - } - :host([aria-checked='true']:focus-visible:not([disabled])) .control { - box-shadow: 0 0 0 2px red, 0 0 0 4px red; - } - :host([disabled]) .label, - :host([readonly]) .label, - :host([readonly]) .control, - :host([disabled]) .control { - cursor: not-allowed; - } - - :host([disabled]) { - opacity: 0.5; - } - - :host([aria-checked='true']) .checked-indicator { - display: block; - } -`; diff --git a/packages/web-components/src/radio/radio.template.ts b/packages/web-components/src/radio/radio.template.ts deleted file mode 100644 index ceb729eb8e4426..00000000000000 --- a/packages/web-components/src/radio/radio.template.ts +++ /dev/null @@ -1,7 +0,0 @@ -import { ElementViewTemplate, html } from '@microsoft/fast-element'; -import { radioTemplate } from '@microsoft/fast-foundation'; -import type { Radio } from './radio.js'; - -export const template: ElementViewTemplate = radioTemplate({ - checkedIndicator: html`
`, -}); diff --git a/packages/web-components/src/radio/radio.ts b/packages/web-components/src/radio/radio.ts deleted file mode 100644 index de75e9633e6e12..00000000000000 --- a/packages/web-components/src/radio/radio.ts +++ /dev/null @@ -1,8 +0,0 @@ -import { attr } from '@microsoft/fast-element'; -import { FASTRadio } from '@microsoft/fast-foundation'; - -/** - * The base class used for constructing a fluent-radio custom element - * @public - */ -export class Radio extends FASTRadio {} From 2cf59cec2397391c19329246ba4bff40d47db385 Mon Sep 17 00:00:00 2001 From: Brian Brady Date: Mon, 20 Mar 2023 12:35:35 -0700 Subject: [PATCH 04/45] input spec init --- packages/web-components/src/input/README.md | 177 ++++++++++++++++++++ 1 file changed, 177 insertions(+) create mode 100644 packages/web-components/src/input/README.md diff --git a/packages/web-components/src/input/README.md b/packages/web-components/src/input/README.md new file mode 100644 index 00000000000000..1ae4c1b1765c1b --- /dev/null +++ b/packages/web-components/src/input/README.md @@ -0,0 +1,177 @@ +# Input + +> An implementation of an [input](https://w3c.github.io/html-reference/input.text.html) as a form-connected web-component. + +
+ +## **Design Spec** + +[Link to Input Design Spec in Figma](https://www.figma.com/file/TvHmWjZYxwtI9Tz6v5BT7E/Input?node-id=2366-657&t=UNSOfCD3St9ffppx-0) + +
+ +## **Engineering Spec** + +Fluent WC3 Input extends from the [FAST Text Field](https://explore.fast.design/components/fast-text-field) and is intended to be as close to the Fluent UI React 9 Input implementation as possible. However, due to the nature of web components there will not be 100% parity between the two. + +
+ +## Class: `Input` + +
+ +### **Component Name** + +`` + +
+ +### **Variables** + +| Name | Description | Type | +| ----------------- | ------------------------------- | ---------------------------------------------------------------------------------------------------------------- | +| `InputSize` | Size variations for input | `{ small: "small", medium: "medium", large: "large" }` | +| `InputAppearance` | Appearance variations for input | `{ outline: "outline", underline: "underline", filledLighter: "filled-lighter", filledDarker: "filled-darker" }` | +| `TextFieldType` | Input types | `{ email: "email", password: "password", tel: "tel", text: "text", url: "url" }` | +| `InputLayout` | Layout variations for input | `{ block: "block", inline: "inline"` | + +
+ +### **Fields** + +| Name | Privacy | Type | Default | Description | +| ------------- | ------- | ----------------- | -------------------- | ----------------------------------------------------------------------------------------------------------------------------------- | +| `appearance` | public | `InputAppearance` | `outline` | Sets appearance of input. | +| `autofocus` | public | `boolean` | `false` | Indicates element should get focus after the page finishes loading.. | +| `disabled` | public | `boolean` | `false` | Disables input | +| `layout` | public | `InputLayout` | `InputLayout.block` | Sets layout display property on input | +| `list` | public | `string` | | Allows associating a `datalist` to an element by `id` | +| `maxlength` | public | `number` | | The maximum number of characters a user can enter | +| `minlength` | public | `number` | | The minimum number of characters a user can enter | +| `name` | public | `number` | | The name of the control | +| `pattern` | public | `string` | | A regular expression the input's contents must match in order to be valid | +| `placeholder` | public | `string` | | An exemplar value to display in the input field whenever it is empty | +| `readonly` | public | `boolean` | `false` | The text field should be submitted with the form but should not be editable | +| `required` | public | `boolean` | `false` | Sets the field as required | +| `size` | public | `InputSize` | `medium` | Sets the size of the text input | +| `spellcheck` | public | `boolean` | `false` | Controls whether or not to enable spell checking for the input field, or if the default spell checking configuration should be used | +| `type` | public | `TextFieldType` | `TextFieldType.text` | Sets the size of the text input | +| `value` | public | `string` | | String value of the text field, can be an empty string | + +
+ +### **Events** + +| Name | Type | Description | Inherited From | +| -------- | ---- | ---------------------------------- | -------------- | +| `change` | | Fires a custom change event | | +| `input` | | Fires a custom input changed event | | + +
+ +### **Attributes** + +| Name | Field | +| ------------- | ----------- | +| `appearance` | appearance | +| `autofocus` | autofocus | +| `disabled` | disabled | +| `list` | list | +| `maxlength` | maxlength | +| `minlength` | minlength | +| `name` | name | +| `pattern` | pattern | +| `placeholder` | placeholder | +| `readonly ` | readonly | +| `required ` | required | +| `size` | size | +| `spellcheck` | spellcheck | +| `type` | type | +| `value ` | value | + +
+ +### **Slots** + +| Name | Description | +| ------- | ----------------------------------------------------------------------- | +| `start` | used to place content at the start of the input within the input border | +| `end` | used to place content at the end of the input within the input border | +| | The default slot for accordion item content | + +
+
+
+ +## **Accessibility** + +[W3C Text Input Spec](https://w3c.github.io/html-reference/input.text.html) + +
+ +### **WAI-ARIA Roles, States, and Properties** + +- `aria-atomic` + - In ARIA live regions, the global aria-atomic attribute indicates whether assistive technologies such as a screen reader will present all, or only parts of, the changed region based on the change notifications defined by the aria-relevant attribute. +- `aria-busy` + - Indicates an element is being modified and that assistive technologies may want to wait until the changes are complete before informing the user about the update. +- `aria-controls` + - Identifies the element (or elements) whose contents or presence are controlled by the element on which this attribute is set. +- `aria-current` + - A non-null `aria-current` state on an element indicates that this element represents the current item within a container or set of related elements. +- `aria-describedby` + - Identifies the element (or elements) that describes the element on which the attribute is set. +- `aria-details` + - The global `aria-details` attribute identifies the element (or elements) that provide additional information related to the object. +- `aria-disabled` + - Indicates that the element is perceivable but disabled, so it is not editable or otherwise operable. +- `aria-errormessage` + - Identifies the element that provides an error message for that object. +- `aria-flowto` + - Identifies the next element (or elements) in an alternate reading order of content. This allows assistive technology to override the general default of reading in document source order at the user's discretion. +- `aria-haspopup` + - Indicates the availability and type of interactive popup element that can be triggered by the element on which the attribute is set. +- `aria-hidden` + - Indicates whether the element is exposed to an accessibility API. +- `aria-invalid` + - Indicates the entered value does not conform to the format expected by the application. +- `aria-keyshortcuts` + - Indicates keyboard shortcuts that an author has implemented to activate or give focus to an element. +- `aria-label` + - Defines a string value that labels an interactive element. +- `aria-labelledby` + - Identifies the element (or elements) that labels the element it is applied to. +- `aria-live` + - Indicates that an element will be updated, and describes the types of updates the user agents, assistive technologies, and user can expect from the live region. +- `aria-owns` + - Identifies an element (or elements) in order to define a visual, functional, or contextual relationship between a parent and its child elements when the DOM hierarchy cannot be used to represent the relationship. +- `aria-relevant` + - Indicates what notifications the user agent will trigger when the accessibility tree within a live region is modified. +- `aria-roledescription` + - Defines a human-readable, author-localized description for the role of an element. + +
+
+
+ +## **Preparation** + +
+ +### **Fluent Web Component v3 v.s Fluent React 9** + +
+ +**Component and Slot Mapping** + +| Fluent UI React 9 | Fluent Web Components 3 | +| ----------------- | ----------------------- | +| `` | `` | +| `contentBefore` | `start` | +| `contentAfter` | `end` | + +
+ +**Property Mapping** +| Fluent UI React 9 | Fluent Web Components 3 | Description of difference | +| ------------------------- | ---------------------------- | ---------------------------------------------------------------------------------------- | From 79b6bffb115a9b3f0c6fe2f207491ea508d6655e Mon Sep 17 00:00:00 2001 From: Brian Brady Date: Mon, 20 Mar 2023 12:52:39 -0700 Subject: [PATCH 05/45] cleans up spec --- packages/web-components/src/input/README.md | 87 +++++++++++---------- 1 file changed, 44 insertions(+), 43 deletions(-) diff --git a/packages/web-components/src/input/README.md b/packages/web-components/src/input/README.md index 1ae4c1b1765c1b..bd6e7aaac17c8d 100644 --- a/packages/web-components/src/input/README.md +++ b/packages/web-components/src/input/README.md @@ -39,55 +39,58 @@ Fluent WC3 Input extends from the [FAST Text Field](https://explore.fast.design/ ### **Fields** -| Name | Privacy | Type | Default | Description | -| ------------- | ------- | ----------------- | -------------------- | ----------------------------------------------------------------------------------------------------------------------------------- | -| `appearance` | public | `InputAppearance` | `outline` | Sets appearance of input. | -| `autofocus` | public | `boolean` | `false` | Indicates element should get focus after the page finishes loading.. | -| `disabled` | public | `boolean` | `false` | Disables input | -| `layout` | public | `InputLayout` | `InputLayout.block` | Sets layout display property on input | -| `list` | public | `string` | | Allows associating a `datalist` to an element by `id` | -| `maxlength` | public | `number` | | The maximum number of characters a user can enter | -| `minlength` | public | `number` | | The minimum number of characters a user can enter | -| `name` | public | `number` | | The name of the control | -| `pattern` | public | `string` | | A regular expression the input's contents must match in order to be valid | -| `placeholder` | public | `string` | | An exemplar value to display in the input field whenever it is empty | -| `readonly` | public | `boolean` | `false` | The text field should be submitted with the form but should not be editable | -| `required` | public | `boolean` | `false` | Sets the field as required | -| `size` | public | `InputSize` | `medium` | Sets the size of the text input | -| `spellcheck` | public | `boolean` | `false` | Controls whether or not to enable spell checking for the input field, or if the default spell checking configuration should be used | -| `type` | public | `TextFieldType` | `TextFieldType.text` | Sets the size of the text input | -| `value` | public | `string` | | String value of the text field, can be an empty string | - -
+| Name | Privacy | Type | Default | Description | +| --------------- | ------- | ----------------- | -------------------- | ----------------------------------------------------------------------------------------------------------------------------------- | +| `appearance` | public | `InputAppearance` | `outline` | Sets appearance of input. | +| `autofocus` | public | `boolean` | `false` | Indicates element should get focus after the page finishes loading.. | +| `disabled` | public | `boolean` | `false` | Disables input | +| `labelPosition` | public | `boolean` | `false` | Disables input | +| `layout` | public | `InputLayout` | `InputLayout.block` | Sets layout display property on input | +| `list` | public | `string` | | Allows associating a `datalist` to an element by `id` | +| `maxlength` | public | `number` | | The maximum number of characters a user can enter | +| `minlength` | public | `number` | | The minimum number of characters a user can enter | +| `name` | public | `number` | | The name of the control | +| `pattern` | public | `string` | | A regular expression the input's contents must match in order to be valid | +| `placeholder` | public | `string` | | An exemplar value to display in the input field whenever it is empty | +| `readonly` | public | `boolean` | `false` | The text field should be submitted with the form but should not be editable | +| `required` | public | `boolean` | `false` | Sets the field as required | +| `size` | public | `InputSize` | `medium` | Sets the size of the text input | +| `spellcheck` | public | `boolean` | `false` | Controls whether or not to enable spell checking for the input field, or if the default spell checking configuration should be used | +| `type` | public | `TextFieldType` | `TextFieldType.text` | Sets the size of the text input | + +
+ +### **Methods** + +| Name | Privacy | Description | +| ---------- | ------- | ------------------------------------------------- | +| `select` | public | Selects all the text in the text field | +| `validate` | public | {@inheritDoc (FormAssociated:interface).validate} | ### **Events** -| Name | Type | Description | Inherited From | -| -------- | ---- | ---------------------------------- | -------------- | -| `change` | | Fires a custom change event | | -| `input` | | Fires a custom input changed event | | +| Name | Type | Description | Inherited From | +| -------- | ---- | --------------------------- | -------------- | +| `change` | | Fires a custom change event | |
### **Attributes** -| Name | Field | -| ------------- | ----------- | -| `appearance` | appearance | -| `autofocus` | autofocus | -| `disabled` | disabled | -| `list` | list | -| `maxlength` | maxlength | -| `minlength` | minlength | -| `name` | name | -| `pattern` | pattern | -| `placeholder` | placeholder | -| `readonly ` | readonly | -| `required ` | required | -| `size` | size | -| `spellcheck` | spellcheck | -| `type` | type | -| `value ` | value | +| Name | Field | +| ---------------- | -------------- | +| `appearance` | appearance | +| `autofocus` | autofocus | +| `label-position` | label-position | +| `list` | list | +| `maxlength` | maxlength | +| `minlength` | minlength | +| `pattern` | pattern | +| `placeholder` | placeholder | +| `readonly ` | readonly | +| `size` | size | +| `spellcheck` | spellcheck | +| `type` | type |
@@ -156,8 +159,6 @@ Fluent WC3 Input extends from the [FAST Text Field](https://explore.fast.design/ ## **Preparation** -
- ### **Fluent Web Component v3 v.s Fluent React 9**
From 5558b9324da0bdc5ae9604c911e352382f5f3fc8 Mon Sep 17 00:00:00 2001 From: Brian Brady Date: Mon, 20 Mar 2023 12:55:29 -0700 Subject: [PATCH 06/45] formatting --- packages/web-components/src/input/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/web-components/src/input/README.md b/packages/web-components/src/input/README.md index bd6e7aaac17c8d..84a237905b9107 100644 --- a/packages/web-components/src/input/README.md +++ b/packages/web-components/src/input/README.md @@ -175,4 +175,4 @@ Fluent WC3 Input extends from the [FAST Text Field](https://explore.fast.design/ **Property Mapping** | Fluent UI React 9 | Fluent Web Components 3 | Description of difference | -| ------------------------- | ---------------------------- | ---------------------------------------------------------------------------------------- | +| ----------------- | ----------------------- | ------------------------- | From 3c045c3b13f0199bb16450044c0d48a4623b1746 Mon Sep 17 00:00:00 2001 From: Brian Brady Date: Mon, 20 Mar 2023 13:25:49 -0700 Subject: [PATCH 07/45] updates component name to text input --- packages/web-components/src/input/README.md | 115 ++++++-------------- 1 file changed, 36 insertions(+), 79 deletions(-) diff --git a/packages/web-components/src/input/README.md b/packages/web-components/src/input/README.md index 84a237905b9107..45cb8e0784083f 100644 --- a/packages/web-components/src/input/README.md +++ b/packages/web-components/src/input/README.md @@ -1,62 +1,62 @@ -# Input +# TextInput -> An implementation of an [input](https://w3c.github.io/html-reference/input.text.html) as a form-connected web-component. +> An implementation of a [text input](https://w3c.github.io/html-reference/input.text.html) as a form-connected web-component.
## **Design Spec** -[Link to Input Design Spec in Figma](https://www.figma.com/file/TvHmWjZYxwtI9Tz6v5BT7E/Input?node-id=2366-657&t=UNSOfCD3St9ffppx-0) +[Link to Text Input Design Spec in Figma](https://www.figma.com/file/TvHmWjZYxwtI9Tz6v5BT7E/Input?node-id=2366-657&t=UNSOfCD3St9ffppx-0)
## **Engineering Spec** -Fluent WC3 Input extends from the [FAST Text Field](https://explore.fast.design/components/fast-text-field) and is intended to be as close to the Fluent UI React 9 Input implementation as possible. However, due to the nature of web components there will not be 100% parity between the two. +Fluent WC3 Text Input extends from the [FAST Text Field](https://explore.fast.design/components/fast-text-field) and is intended to be as close to the Fluent UI React 9 Input implementation as possible. However, due to the nature of web components there will not be 100% parity between the two.
-## Class: `Input` +## Class: `TextInput`
### **Component Name** -`` +``
### **Variables** -| Name | Description | Type | -| ----------------- | ------------------------------- | ---------------------------------------------------------------------------------------------------------------- | -| `InputSize` | Size variations for input | `{ small: "small", medium: "medium", large: "large" }` | -| `InputAppearance` | Appearance variations for input | `{ outline: "outline", underline: "underline", filledLighter: "filled-lighter", filledDarker: "filled-darker" }` | -| `TextFieldType` | Input types | `{ email: "email", password: "password", tel: "tel", text: "text", url: "url" }` | -| `InputLayout` | Layout variations for input | `{ block: "block", inline: "inline"` | +| Name | Description | Type | +| ------------ | ------------------------------------ | ---------------------------------------------------------------------------------------------------------------- | +| `size` | Size variations for text input | `{ small: "small", medium: "medium", large: "large" }` | +| `appearance` | Appearance variations for text input | `{ outline: "outline", underline: "underline", filledLighter: "filled-lighter", filledDarker: "filled-darker" }` | +| `type` | Text input types | `{ email: "email", password: "password", tel: "tel", text: "text", url: "url" }` | +| `layout` | Layout variations for text input | `{ block: "block", inline: "inline"` |
### **Fields** -| Name | Privacy | Type | Default | Description | -| --------------- | ------- | ----------------- | -------------------- | ----------------------------------------------------------------------------------------------------------------------------------- | -| `appearance` | public | `InputAppearance` | `outline` | Sets appearance of input. | -| `autofocus` | public | `boolean` | `false` | Indicates element should get focus after the page finishes loading.. | -| `disabled` | public | `boolean` | `false` | Disables input | -| `labelPosition` | public | `boolean` | `false` | Disables input | -| `layout` | public | `InputLayout` | `InputLayout.block` | Sets layout display property on input | -| `list` | public | `string` | | Allows associating a `datalist` to an element by `id` | -| `maxlength` | public | `number` | | The maximum number of characters a user can enter | -| `minlength` | public | `number` | | The minimum number of characters a user can enter | -| `name` | public | `number` | | The name of the control | -| `pattern` | public | `string` | | A regular expression the input's contents must match in order to be valid | -| `placeholder` | public | `string` | | An exemplar value to display in the input field whenever it is empty | -| `readonly` | public | `boolean` | `false` | The text field should be submitted with the form but should not be editable | -| `required` | public | `boolean` | `false` | Sets the field as required | -| `size` | public | `InputSize` | `medium` | Sets the size of the text input | -| `spellcheck` | public | `boolean` | `false` | Controls whether or not to enable spell checking for the input field, or if the default spell checking configuration should be used | -| `type` | public | `TextFieldType` | `TextFieldType.text` | Sets the size of the text input | +| Name | Privacy | Type | Default | Description | +| --------------- | ------- | ----------------- | ----------------------- | ---------------------------------------------------------------------------------------------------------------------------------- | +| `appearance` | public | `InputAppearance` | `outline` | Sets appearance of text input. | +| `autofocus` | public | `boolean` | `false` | Indicates element should get focus after the page finishes loading.. | +| `disabled` | public | `boolean` | `false` | Disables text input | +| `labelPosition` | public | `boolean` | `false` | Disables text input | +| `layout` | public | `InputLayout` | `TextInputLayout.block` | Sets layout display property on text input | +| `list` | public | `string` | | Allows associating a `datalist` to an element by `id` | +| `maxlength` | public | `number` | | The maximum number of characters a user can enter | +| `minlength` | public | `number` | | The minimum number of characters a user can enter | +| `name` | public | `number` | | The name of the control | +| `pattern` | public | `string` | | A regular expression the text input's contents must match in order to be valid | +| `placeholder` | public | `string` | | An exemplar value to display in the text input field whenever it is empty | +| `readonly` | public | `boolean` | `false` | The text input should be submitted with the form but should not be editable | +| `required` | public | `boolean` | `false` | Sets the text input as required | +| `size` | public | `InputSize` | `medium` | Sets the size of the text input | +| `spellcheck` | public | `boolean` | `false` | Controls whether or not to enable spell checking for the text input, or if the default spell checking configuration should be used | +| `type` | public | `TextInputType` | `TextInputType.text` | Sets the size of the text input |
@@ -96,11 +96,11 @@ Fluent WC3 Input extends from the [FAST Text Field](https://explore.fast.design/ ### **Slots** -| Name | Description | -| ------- | ----------------------------------------------------------------------- | -| `start` | used to place content at the start of the input within the input border | -| `end` | used to place content at the end of the input within the input border | -| | The default slot for accordion item content | +| Name | Description | +| ------- | ---------------------------------------------------------------------------- | +| `start` | used to place content at the start of the text input within the input border | +| `end` | used to place content at the end of the text input within the input border | +| | The default slot for text input content |

@@ -114,44 +114,7 @@ Fluent WC3 Input extends from the [FAST Text Field](https://explore.fast.design/ ### **WAI-ARIA Roles, States, and Properties** -- `aria-atomic` - - In ARIA live regions, the global aria-atomic attribute indicates whether assistive technologies such as a screen reader will present all, or only parts of, the changed region based on the change notifications defined by the aria-relevant attribute. -- `aria-busy` - - Indicates an element is being modified and that assistive technologies may want to wait until the changes are complete before informing the user about the update. -- `aria-controls` - - Identifies the element (or elements) whose contents or presence are controlled by the element on which this attribute is set. -- `aria-current` - - A non-null `aria-current` state on an element indicates that this element represents the current item within a container or set of related elements. -- `aria-describedby` - - Identifies the element (or elements) that describes the element on which the attribute is set. -- `aria-details` - - The global `aria-details` attribute identifies the element (or elements) that provide additional information related to the object. -- `aria-disabled` - - Indicates that the element is perceivable but disabled, so it is not editable or otherwise operable. -- `aria-errormessage` - - Identifies the element that provides an error message for that object. -- `aria-flowto` - - Identifies the next element (or elements) in an alternate reading order of content. This allows assistive technology to override the general default of reading in document source order at the user's discretion. -- `aria-haspopup` - - Indicates the availability and type of interactive popup element that can be triggered by the element on which the attribute is set. -- `aria-hidden` - - Indicates whether the element is exposed to an accessibility API. -- `aria-invalid` - - Indicates the entered value does not conform to the format expected by the application. -- `aria-keyshortcuts` - - Indicates keyboard shortcuts that an author has implemented to activate or give focus to an element. -- `aria-label` - - Defines a string value that labels an interactive element. -- `aria-labelledby` - - Identifies the element (or elements) that labels the element it is applied to. -- `aria-live` - - Indicates that an element will be updated, and describes the types of updates the user agents, assistive technologies, and user can expect from the live region. -- `aria-owns` - - Identifies an element (or elements) in order to define a visual, functional, or contextual relationship between a parent and its child elements when the DOM hierarchy cannot be used to represent the relationship. -- `aria-relevant` - - Indicates what notifications the user agent will trigger when the accessibility tree within a live region is modified. -- `aria-roledescription` - - Defines a human-readable, author-localized description for the role of an element. +This component supports ARIA attributes that inherit from the [ARIA Global States and Properties](https://www.w3.org/TR/wai-aria-1.2/#global_states).

@@ -170,9 +133,3 @@ Fluent WC3 Input extends from the [FAST Text Field](https://explore.fast.design/ | `` | `` | | `contentBefore` | `start` | | `contentAfter` | `end` | - -
- -**Property Mapping** -| Fluent UI React 9 | Fluent Web Components 3 | Description of difference | -| ----------------- | ----------------------- | ------------------------- | From 237096724298e6e09218b2f2e25caf2bebad0e2c Mon Sep 17 00:00:00 2001 From: Brian Brady Date: Mon, 20 Mar 2023 13:39:31 -0700 Subject: [PATCH 08/45] updates component name in spec --- packages/web-components/src/input/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/web-components/src/input/README.md b/packages/web-components/src/input/README.md index 45cb8e0784083f..1461fca61850bc 100644 --- a/packages/web-components/src/input/README.md +++ b/packages/web-components/src/input/README.md @@ -130,6 +130,6 @@ This component supports ARIA attributes that inherit from the [ARIA Global State | Fluent UI React 9 | Fluent Web Components 3 | | ----------------- | ----------------------- | -| `` | `` | +| `` | `` | | `contentBefore` | `start` | | `contentAfter` | `end` | From c6d99b9702f9678ae649c61e62ef094ff6b99893 Mon Sep 17 00:00:00 2001 From: brianchristopherbrady Date: Tue, 18 Jul 2023 00:13:42 -0700 Subject: [PATCH 09/45] dialog init --- packages/web-components/src/dialog/README.md | 63 +++++++++ packages/web-components/src/dialog/define.ts | 4 + .../src/dialog/dialog.definition.ts | 17 +++ .../src/dialog/dialog.stories.ts | 120 ++++++++++++++++++ .../src/dialog/dialog.styles.ts | 106 ++++++++++++++++ .../src/dialog/dialog.template.ts | 58 +++++++++ packages/web-components/src/dialog/dialog.ts | 21 +++ packages/web-components/src/dialog/index.ts | 4 + 8 files changed, 393 insertions(+) create mode 100644 packages/web-components/src/dialog/README.md create mode 100644 packages/web-components/src/dialog/define.ts create mode 100644 packages/web-components/src/dialog/dialog.definition.ts create mode 100644 packages/web-components/src/dialog/dialog.stories.ts create mode 100644 packages/web-components/src/dialog/dialog.styles.ts create mode 100644 packages/web-components/src/dialog/dialog.template.ts create mode 100644 packages/web-components/src/dialog/dialog.ts create mode 100644 packages/web-components/src/dialog/index.ts diff --git a/packages/web-components/src/dialog/README.md b/packages/web-components/src/dialog/README.md new file mode 100644 index 00000000000000..6ccd8dd868fc30 --- /dev/null +++ b/packages/web-components/src/dialog/README.md @@ -0,0 +1,63 @@ +# Dialog + +> Dialog is a window overlaid on either the primary window or another dialog window. Windows under a modal dialog are inert. That is, users cannot interact with content outside an active dialog window. Inert content outside an active dialog is typically visually obscured or dimmed so it is difficult to discern, and in some implementations, attempts to interact with the inert content cause the dialog to close. + +## **Design Spec** + +[Link to Dialog in Figma](https://www.figma.com/file/jtF47yOXDxkI00ZkydE999/Dialog?type=design&node-id=2605%3A15263&mode=dev) + +## **Engineering Spec** + +Fluent WC3 Dialog has feature parity with the Fluent UI React 9 Dialog implementation but not direct parity. + +## Class: `Dialog` + +
+ +### **Component Name** + +`` + +# **Attributes** + +| Name | Privacy | Type | Default | Description | +| ------------- | ------- | --------- | ------- | ------------------------------------------------ | +| `modal` | public | `boolean` | `false` | Renders dialog as a modal | +| `alert` | public | `boolean` | `false` | Renders dialog as an alert modal | +| `hidden` | public | `boolean` | `false` | Sets the visibility of the dialog | +| `noFocusTrap` | public | `boolean` | `false` | Indicates that the dialog should not trap focus. | + +
+ +### **Methods** + +| Name | Privacy | Description | Parameters | Return | Inherited From | +| ------ | ------- | ------------------------------ | ---------- | ------ | -------------- | +| `hide` | public | The method to hide the dialog. | | void | FASTDialog | +| `show` | public | The method to show the dialog. | | void | FASTDialog | + +
+ +## **Preparation** + +
+ +### **Fluent Web Component v3 v.s Fluent React 9** + +
+ +**Component and Slot Mapping** + +| Fluent UI React 9 | Fluent Web Components 3 | +| ----------------- | ----------------------- | +| `` | `` | + +
+ +**Property Mapping** + +| Fluent UI React 9 | Fluent Web Components 3 | Description of difference | +| --------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ----------------------- | ----------------------------------------------------------------------------------------------------------------------------------------- | ---------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| `modalType: 'alert' | 'modal' | 'non-modal'` | `alert: boolean`, `modal: boolean` | In FUIR9, the modalType prop accepts a string value ('alert', 'modal', or 'non-modal') to specify the modal behavior. In FUIWC3, separate boolean props (alert and modal) are used to indicate whether the component should behave as an alert or a modal. | +| `onOpenChange` | `onHiddenChange` | In FUIR9, the onOpenChange event is emitted when the open prop of a component changes, indicating a change in the component's open state. | +| In FUIWC3, the onHiddenChange event is emitted when the hidden property or attribute of a component changes, indicating a change in the component's visibility state. | diff --git a/packages/web-components/src/dialog/define.ts b/packages/web-components/src/dialog/define.ts new file mode 100644 index 00000000000000..55ac9cde847354 --- /dev/null +++ b/packages/web-components/src/dialog/define.ts @@ -0,0 +1,4 @@ +import { FluentDesignSystem } from '../fluent-design-system.js'; +import { definition } from './dialog.definition.js'; + +definition.define(FluentDesignSystem.registry); diff --git a/packages/web-components/src/dialog/dialog.definition.ts b/packages/web-components/src/dialog/dialog.definition.ts new file mode 100644 index 00000000000000..103ccc7ab3e0d6 --- /dev/null +++ b/packages/web-components/src/dialog/dialog.definition.ts @@ -0,0 +1,17 @@ +import { FluentDesignSystem } from '../fluent-design-system.js'; +import { Dialog } from './dialog.js'; +import { template } from './dialog.template.js'; +import { styles } from './dialog.styles.js'; + +/** + * The Fluent Dialog Element + * + * @public + * @remarks + * HTML Element: \ + */ +export const definition = Dialog.compose({ + name: `${FluentDesignSystem.prefix}-dialog`, + template, + styles, +}); diff --git a/packages/web-components/src/dialog/dialog.stories.ts b/packages/web-components/src/dialog/dialog.stories.ts new file mode 100644 index 00000000000000..cdc3b792185dab --- /dev/null +++ b/packages/web-components/src/dialog/dialog.stories.ts @@ -0,0 +1,120 @@ +import { html } from '@microsoft/fast-element'; +import type { Args, Meta } from '@storybook/html'; +import { renderComponent } from '../helpers.stories.js'; +import type { Dialog, Dialog as FluentDialog } from './dialog.js'; +import './define.js'; +import '../button/define.js'; +import '../text/define.js'; + +type DialogStoryArgs = Args & FluentDialog; +type DialogStoryMeta = Meta; + +const dismissed16Regular = html` + +`; + +const subtract20Filled = html` + +`; + +const closeDialog = () => { + const dialog = document.getElementById('dialog-default') as Dialog; + dialog.hide(); +}; + +const openDialog = () => { + const dialog = document.getElementById('dialog-default') as Dialog; + dialog.show(); +}; + +const dialogTemplate = html` +
+ +
+ Open Dialog + x.modal} ?alert=${x => x.alert} hidden> +
Dialog Header
+
Dialog content
+
+ Close Drawer + Do something +
+
+
+
+`; + +export default { + title: 'Components/Dialog', + args: { + modal: false, + alert: false, + hidden: false, + }, + argTypes: { + hidden: { + description: 'Renders dialog as a modal', + table: { + defaultValue: { + summary: false, + }, + }, + control: 'boolean', + }, + modal: { + description: 'Renders dialog as an modal', + table: { + defaultValue: { + summary: false, + }, + }, + control: 'boolean', + }, + alert: { + description: 'Renders dialog as an alert', + table: { + defaultValue: { + summary: false, + }, + }, + control: 'boolean', + }, + }, +} as DialogStoryMeta; + +export const Default = renderComponent(dialogTemplate).bind({}); diff --git a/packages/web-components/src/dialog/dialog.styles.ts b/packages/web-components/src/dialog/dialog.styles.ts new file mode 100644 index 00000000000000..b9bbacd5e4ef1a --- /dev/null +++ b/packages/web-components/src/dialog/dialog.styles.ts @@ -0,0 +1,106 @@ +import { + colorNeutralBackground1, + colorTransparentStroke, + fontFamilyBase, + fontSizeBase300, + fontSizeBase400, + fontWeightRegular, + fontWeightSemibold, + lineHeightBase300, + lineHeightBase400, + shadow64, + spacingHorizontalL, + spacingHorizontalXXL, + spacingVerticalL, + spacingVerticalXS, + strokeWidthThin, +} from '@fluentui/web-components'; +import { css } from '@microsoft/fast-element'; +import { display } from '@microsoft/fast-foundation'; + +/** Dialog styles + * @public + */ +export const styles = css` + ${display('flex')} + :host([hidden]) { + display: none; + } + + :host { + } + + .overlay { + position: fixed; + top: 0; + left: 0; + right: 0; + bottom: 0; + background: rgba(0, 0, 0, 0.3); + touch-action: none; + } + + .positioning-region { + display: flex; + justify-content: center; + position: fixed; + top: 0; + bottom: 0; + left: 0; + right: 0; + overflow: auto; + } + + .control { + background: ${colorNeutralBackground1}; + border: ${strokeWidthThin} solid ${colorTransparentStroke}; + z-index: 2; + margin: auto auto; + width: 100%; + max-width: 600px; + max-height: 100vh; + box-shadow: ${shadow64}; + } + + .header { + display: flex; + justify-content: space-between; + padding-bottom: ${spacingVerticalXS}; + font-size: ${fontSizeBase400}; + line-height: ${lineHeightBase400}; + font-weight: ${fontWeightSemibold}; + font-family: ${fontFamilyBase}; + padding: ${spacingHorizontalXXL}; + } + + .content { + display: flex; + align-items: flex-start; + width: 100%; + padding: 0 ${spacingHorizontalXXL}; + vertical-align: top; + height: fit-content; + min-height: 32px; + font-size: ${fontSizeBase300}; + line-height: ${lineHeightBase300}; + font-weight: ${fontWeightRegular}; + font-family: ${fontFamilyBase}; + } + + .actions { + display: flex; + flex-direction: row; + padding: ${spacingVerticalXS} ${spacingHorizontalXXL} ${spacingHorizontalXXL} ${spacingHorizontalXXL}; + align-items: flex-end; + } + + @media screen and (max-width: 480px) { + .control { + max-width: 100%; + width: 100vh; + } + .actions { + flex-direction: column; + } + } +`; diff --git a/packages/web-components/src/dialog/dialog.template.ts b/packages/web-components/src/dialog/dialog.template.ts new file mode 100644 index 00000000000000..e5d448d22efd10 --- /dev/null +++ b/packages/web-components/src/dialog/dialog.template.ts @@ -0,0 +1,58 @@ +import { ElementViewTemplate, html, ref, when } from '@microsoft/fast-element'; +import type { Dialog } from './dialog.js'; + +const dismissed16Regular = html` + +`; + +/** + * Template for the Dialog component + * @public + */ +export const template: ElementViewTemplate = html`
+ ${when( + x => x.modal || x.alert, + html` `, + )} + +
`; diff --git a/packages/web-components/src/dialog/dialog.ts b/packages/web-components/src/dialog/dialog.ts new file mode 100644 index 00000000000000..30aa7fce2863b1 --- /dev/null +++ b/packages/web-components/src/dialog/dialog.ts @@ -0,0 +1,21 @@ +import { attr } from '@microsoft/fast-element'; +import { FASTDialog } from '@microsoft/fast-foundation'; + +/** + * @class Dialog component + */ + +export class Dialog extends FASTDialog { + @attr({ mode: 'boolean' }) + public alert: boolean = false; + + public dismiss(): void { + super.dismiss(); + if (this.alert) return; + this.hidden = true; + } + + public hiddenChanged() { + this.$emit('onHiddenChange', this.hidden); + } +} diff --git a/packages/web-components/src/dialog/index.ts b/packages/web-components/src/dialog/index.ts new file mode 100644 index 00000000000000..12f8a223acb9b5 --- /dev/null +++ b/packages/web-components/src/dialog/index.ts @@ -0,0 +1,4 @@ +export * from './dialog.js'; +export { definition as DialogDefinition } from './dialog.definition.js'; +export { template as DialogTemplate } from './dialog.template.js'; +export { styles as DialogStyles } from './dialog.styles.js'; From 8e367ef2cf268a010a5808ada349fb4d30d5fb3a Mon Sep 17 00:00:00 2001 From: brianchristopherbrady Date: Tue, 18 Jul 2023 14:35:48 -0700 Subject: [PATCH 10/45] dialog: updates stories, styles, and docs --- packages/web-components/src/dialog/README.md | 21 +- .../src/dialog/dialog.stories.ts | 217 ++++++++++++++---- .../src/dialog/dialog.styles.ts | 81 +++++-- .../src/dialog/dialog.template.ts | 22 +- packages/web-components/src/dialog/dialog.ts | 28 ++- 5 files changed, 288 insertions(+), 81 deletions(-) diff --git a/packages/web-components/src/dialog/README.md b/packages/web-components/src/dialog/README.md index 6ccd8dd868fc30..373c2f753baed8 100644 --- a/packages/web-components/src/dialog/README.md +++ b/packages/web-components/src/dialog/README.md @@ -46,18 +46,21 @@ Fluent WC3 Dialog has feature parity with the Fluent UI React 9 Dialog implement
-**Component and Slot Mapping** +**Component, Element, and Slot Mapping** -| Fluent UI React 9 | Fluent Web Components 3 | -| ----------------- | ----------------------- | -| `` | `` | +| Fluent UI React 9 | Fluent Web Components 3 | Description of difference | +| ----------------- | ------------------------ | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| `` | `` | tag name | +| `` | methods: `hide() show()` | In the React version of our components, a "DialogTrigger" component is utilized as part of a composite component of Dialog. The DialogTrigger component provides functionality for toggling the visibility of the Dialog component.
In the Web Component version does not include a dialog trigger. Instead, it expects the user to directly access methods on the Dialog class or utilize CSS to control the visibility of the dialog component. | +| `` | `.overlay` | In the React version of our components, the DialogSurface component is used as part of the composite Dialog component to represent the dimmed background of the dialog.
In the Web Component version utilizes an HTML element with a class of ".overlay" as part of the Dialog component to achieve the same effect of a dimmed background for the dialog. | +| `` | `slot: title` | In the React version of our components, the component is used to represent the title of the dialog.
In the Web Component version, the title is provided through a element with the name attribute set to "title". This allows users to insert their own title content into the dialog component. | +| `` | `slot: actions` | In the React version of our components, the component is used to represent the actions or buttons within the dialog.
In the Web Component version, the actions or buttons are provided through a element with the name attribute set to "actions". This allows users to insert their own actions or buttons into the dialog component. |
**Property Mapping** -| Fluent UI React 9 | Fluent Web Components 3 | Description of difference | -| --------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ----------------------- | ----------------------------------------------------------------------------------------------------------------------------------------- | ---------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -| `modalType: 'alert' | 'modal' | 'non-modal'` | `alert: boolean`, `modal: boolean` | In FUIR9, the modalType prop accepts a string value ('alert', 'modal', or 'non-modal') to specify the modal behavior. In FUIWC3, separate boolean props (alert and modal) are used to indicate whether the component should behave as an alert or a modal. | -| `onOpenChange` | `onHiddenChange` | In FUIR9, the onOpenChange event is emitted when the open prop of a component changes, indicating a change in the component's open state. | -| In FUIWC3, the onHiddenChange event is emitted when the hidden property or attribute of a component changes, indicating a change in the component's visibility state. | +| Fluent UI React 9 | Fluent Web Components 3 | Description of difference | +| ---------------------------------------------- | ---------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | +| `modalType: 'alert' \| 'modal' \| 'non-modal'` | `alert: boolean`, `modal: boolean` | In FUIR9, the modalType prop accepts a string value ('alert', 'modal', or 'non-modal') to specify the modal behavior. In FUIWC3, separate boolean props (alert and modal) are used to indicate whether the component should behave as an alert or a modal. | +| `onOpenChange` | `onHiddenChange` | In FUIR9, the onOpenChange event is emitted when the open prop of a component changes, indicating a change in the component's open state. FUIWC3, the onHiddenChange event is emitted when the hidden property or attribute of a component changes, indicating a change in the component's visibility state. | diff --git a/packages/web-components/src/dialog/dialog.stories.ts b/packages/web-components/src/dialog/dialog.stories.ts index cdc3b792185dab..0cadcddad7669d 100644 --- a/packages/web-components/src/dialog/dialog.stories.ts +++ b/packages/web-components/src/dialog/dialog.stories.ts @@ -1,7 +1,7 @@ import { html } from '@microsoft/fast-element'; import type { Args, Meta } from '@storybook/html'; import { renderComponent } from '../helpers.stories.js'; -import type { Dialog, Dialog as FluentDialog } from './dialog.js'; +import type { Dialog as FluentDialog } from './dialog.js'; import './define.js'; import '../button/define.js'; import '../text/define.js'; @@ -9,71 +9,55 @@ import '../text/define.js'; type DialogStoryArgs = Args & FluentDialog; type DialogStoryMeta = Meta; -const dismissed16Regular = html` +const DismissCircle24Regular = html` `; -const subtract20Filled = html` - -`; - -const closeDialog = () => { - const dialog = document.getElementById('dialog-default') as Dialog; +const closeDialog = (e: Event, id: string) => { + const dialog = document.getElementById(id) as FluentDialog; dialog.hide(); }; -const openDialog = () => { - const dialog = document.getElementById('dialog-default') as Dialog; +const openDialog = (e: Event, id: string) => { + const dialog = document.getElementById(id) as FluentDialog; dialog.show(); }; const dialogTemplate = html` +
- -
- Open Dialog - x.modal} ?alert=${x => x.alert} hidden> -
Dialog Header
-
Dialog content
-
- Close Drawer - Do something -
+ openDialog(e, 'dialog-default')}>Open Dialog + x.modal} + ?alert=${x => x.alert} + ?no-trap-focus=${x => x.noFocusTrap} + hidden + > +
Dialog Title
+
Dialog is a window overlaid on either the primary window or another dialog window. Windows under a modal dialog are inert. That is, users cannot interact with content outside an active dialog window. Inert content outside an active dialog is typically visually obscured or dimmed so it is difficult to discern, and in some implementations, attempts to interact with the inert content cause the dialog to close.
+ Close Drawer + Do Something
@@ -85,6 +69,7 @@ export default { modal: false, alert: false, hidden: false, + noTrapFocus: false, }, argTypes: { hidden: { @@ -114,7 +99,145 @@ export default { }, control: 'boolean', }, + noFocusTrap: { + description: 'removes trap focus', + table: { + defaultValue: { + summary: false, + }, + }, + control: 'boolean', + }, }, } as DialogStoryMeta; export const Default = renderComponent(dialogTemplate).bind({}); + +export const Modal = renderComponent(html` +
+ openDialog(e, 'dialog-modal')}>Open Dialog + +
+`); + +export const Alert = renderComponent(html` +
+ openDialog(e, 'dialog-alert')}>Open Dialog + +
+`); + +export const ScrollingLongContent = renderComponent(html` +
+ openDialog(e, 'dialog-longcontent')}>Open Dialog + +
+`); + +export const CustomCloseIcon = renderComponent(html` +
+ openDialog(e, 'dialog-closeicon')}>Open Dialog + +
+`); + +export const NoFocusTrap = renderComponent(html` +
+ openDialog(e, 'dialog-nofocustrap')}>Open Dialog + +
+`); diff --git a/packages/web-components/src/dialog/dialog.styles.ts b/packages/web-components/src/dialog/dialog.styles.ts index b9bbacd5e4ef1a..ff2c593741bc7a 100644 --- a/packages/web-components/src/dialog/dialog.styles.ts +++ b/packages/web-components/src/dialog/dialog.styles.ts @@ -1,4 +1,5 @@ import { + borderRadiusXLarge, colorNeutralBackground1, colorTransparentStroke, fontFamilyBase, @@ -9,10 +10,14 @@ import { lineHeightBase300, lineHeightBase400, shadow64, - spacingHorizontalL, + spacingHorizontalS, + spacingHorizontalXL, + spacingHorizontalXS, spacingHorizontalXXL, - spacingVerticalL, + spacingVerticalM, + spacingVerticalS, spacingVerticalXS, + spacingVerticalXXL, strokeWidthThin, } from '@fluentui/web-components'; import { css } from '@microsoft/fast-element'; @@ -48,7 +53,6 @@ export const styles = css` bottom: 0; left: 0; right: 0; - overflow: auto; } .control { @@ -58,40 +62,82 @@ export const styles = css` margin: auto auto; width: 100%; max-width: 600px; - max-height: 100vh; + border-radius: ${borderRadiusXLarge}; box-shadow: ${shadow64}; + max-height: 100vh; + height: fit-content; + overflow: unset; + position: fixed; + top: 0; + bottom: 0; + left: 0; + right: 0; + } + + .root { + box-sizing: border-box; + display: grid; + /* flex-direction: column; */ + grid-template-rows: auto 1fr auto; + grid-template-columns: 1fr 1fr auto; + overflow: unset; + max-height: calc(100vh - 48px); } .header { - display: flex; - justify-content: space-between; + grid-column-start: 1; + grid-row-end: 1; + grid-row-start: 1; padding-bottom: ${spacingVerticalXS}; font-size: ${fontSizeBase400}; line-height: ${lineHeightBase400}; font-weight: ${fontWeightSemibold}; font-family: ${fontFamilyBase}; - padding: ${spacingHorizontalXXL}; + padding: ${spacingVerticalXXL} ${spacingHorizontalXS} ${spacingVerticalXS} ${spacingHorizontalXXL}; + height: fit-content; + } + + .close { + align-self: start; + justify-self: end; + grid-column-start: 3; + grid-row-end: 1; + grid-row-start: 1; + padding: ${spacingVerticalXXL} ${spacingHorizontalXL} ${spacingVerticalS} ${spacingHorizontalXXL}; } .content { - display: flex; - align-items: flex-start; - width: 100%; + grid-row-end: 2; + grid-row-start: 2; + grid-column-start: 1; + grid-column-end: 4; padding: 0 ${spacingHorizontalXXL}; vertical-align: top; - height: fit-content; min-height: 32px; font-size: ${fontSizeBase300}; line-height: ${lineHeightBase300}; font-weight: ${fontWeightRegular}; font-family: ${fontFamilyBase}; + overflow-y: auto; + box-sizing: border-box; } .actions { display: flex; flex-direction: row; - padding: ${spacingVerticalXS} ${spacingHorizontalXXL} ${spacingHorizontalXXL} ${spacingHorizontalXXL}; - align-items: flex-end; + padding: ${spacingVerticalS} ${spacingHorizontalXXL} ${spacingHorizontalXXL} ${spacingHorizontalXXL}; + /* justify-content: flex-end; */ + /* align-items: center; */ + height: fit-content; + column-gap: ${spacingHorizontalS}; + + box-sizing: border-box; + grid-column-start: 2; + grid-row-start: 3; + justify-self: end; + grid-column-end: 4; + row-gap: 8px; + column-gap: 8px; } @media screen and (max-width: 480px) { @@ -100,7 +146,16 @@ export const styles = css` width: 100vh; } .actions { + display: grid; + grid-template-columns: 1fr 1fr auto; + grid-template-rows: auto 1fr auto; flex-direction: column; + max-width: 100vw; + justify-self: stretch; + padding-top: ${spacingVerticalXXL}; + } + .actions fluent-button::part(control) { + width: 100%; } } `; diff --git a/packages/web-components/src/dialog/dialog.template.ts b/packages/web-components/src/dialog/dialog.template.ts index e5d448d22efd10..3c8d42010116fb 100644 --- a/packages/web-components/src/dialog/dialog.template.ts +++ b/packages/web-components/src/dialog/dialog.template.ts @@ -37,22 +37,24 @@ export const template: ElementViewTemplate = html`
x.ariaLabel}" ${ref('dialog')} > -
- +
+
+ +
${when( x => !x.modal && !x.alert, html` - x.dismiss()}> - ${dismissed16Regular} + x.dismiss()}> + ${dismissed16Regular} `, )} -
-
- -
-
- +
+ +
+
+ +
`; diff --git a/packages/web-components/src/dialog/dialog.ts b/packages/web-components/src/dialog/dialog.ts index 30aa7fce2863b1..ddf3e10ab1b467 100644 --- a/packages/web-components/src/dialog/dialog.ts +++ b/packages/web-components/src/dialog/dialog.ts @@ -2,19 +2,43 @@ import { attr } from '@microsoft/fast-element'; import { FASTDialog } from '@microsoft/fast-foundation'; /** - * @class Dialog component + * Dialog component that extends the FASTDialog class. + * It provides additional functionality for handling alerts and emitting events on hidden state changes. + * + * @public + * @extends FASTDialog */ - export class Dialog extends FASTDialog { + /** + * Indicates whether the dialog is an alert. + * + * @public + * @defaultValue false + * @remarks + * HTML Attribute: alert + */ @attr({ mode: 'boolean' }) public alert: boolean = false; + /** + * Dismisses the dialog. + * If the dialog is an alert, it only triggers the super.dismiss() method. + * Otherwise, it sets the hidden property to true. + * + * @public + */ public dismiss(): void { super.dismiss(); if (this.alert) return; this.hidden = true; } + /** + * Event handler for the hiddenChanged event. + * Emits the onHiddenChange event with the current hidden state. + * + * @public + */ public hiddenChanged() { this.$emit('onHiddenChange', this.hidden); } From 7e6a2405f88e0f79b8720f8968d13960f31d20e9 Mon Sep 17 00:00:00 2001 From: brianchristopherbrady Date: Tue, 18 Jul 2023 15:36:02 -0700 Subject: [PATCH 11/45] dialog: updates styles --- .../src/dialog/dialog.stories.ts | 58 +++++++++---------- .../src/dialog/dialog.styles.ts | 15 +++-- 2 files changed, 36 insertions(+), 37 deletions(-) diff --git a/packages/web-components/src/dialog/dialog.stories.ts b/packages/web-components/src/dialog/dialog.stories.ts index 0cadcddad7669d..5f0fa483681efd 100644 --- a/packages/web-components/src/dialog/dialog.stories.ts +++ b/packages/web-components/src/dialog/dialog.stories.ts @@ -56,7 +56,7 @@ const dialogTemplate = html` slot="actions" appearance="primary" @click="${(e: Event, c) => closeDialog(e, 'dialog-default')}">Close Drawer - Do Something
@@ -122,12 +122,10 @@ export const Modal = renderComponent(html` When this type of dialog is open, the rest of the page is dimmed out and cannot be interacted with. The tab sequence is kept within the dialog and moving the focus outside the dialog will imply closing it. -
- Close Drawer - Do Something -
+ Close Drawer + Do Something
`); @@ -142,12 +140,10 @@ export const Alert = renderComponent(html` message and acquire a response. By default clicking on backdrop and pressing Escape will not dismiss an alert Dialog. -
- Close Drawer - Do Something -
+ Close Drawer + Do Something
`); @@ -199,12 +195,13 @@ export const ScrollingLongContent = renderComponent(html` odio mauris, a gravida nisi volutpat in. Aliquam at maximus felis. Vestibulum convallis dignissim urna id gravida. -
- Close Drawer - Do Something -
+ Close Drawer + Do Something `); @@ -216,12 +213,10 @@ export const CustomCloseIcon = renderComponent(html`
Custom Close Icon Dialog Title
${DismissCircle24Regular}
Dialog content
-
- Close Drawer - Do Something -
+ Close Drawer + Do Something `); @@ -232,12 +227,13 @@ export const NoFocusTrap = renderComponent(html` `); diff --git a/packages/web-components/src/dialog/dialog.styles.ts b/packages/web-components/src/dialog/dialog.styles.ts index ff2c593741bc7a..99a4da18c38cc1 100644 --- a/packages/web-components/src/dialog/dialog.styles.ts +++ b/packages/web-components/src/dialog/dialog.styles.ts @@ -138,6 +138,8 @@ export const styles = css` grid-column-end: 4; row-gap: 8px; column-gap: 8px; + grid-template-columns: 1fr 1fr auto; + grid-template-rows: auto 1fr auto; } @media screen and (max-width: 480px) { @@ -145,16 +147,17 @@ export const styles = css` max-width: 100%; width: 100vh; } - .actions { - display: grid; - grid-template-columns: 1fr 1fr auto; + .root { + max-width: 100vw; grid-template-rows: auto 1fr auto; + } + .actions { + display: flex; + grid-column-start: 1; flex-direction: column; max-width: 100vw; - justify-self: stretch; padding-top: ${spacingVerticalXXL}; - } - .actions fluent-button::part(control) { + justify-self: stretch; width: 100%; } } From bd041b9725efc1df5dab63f0884bfbee9c089912 Mon Sep 17 00:00:00 2001 From: brianchristopherbrady Date: Tue, 18 Jul 2023 15:37:15 -0700 Subject: [PATCH 12/45] dialog: removes dead code, cleans up --- packages/web-components/src/dialog/dialog.styles.ts | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/packages/web-components/src/dialog/dialog.styles.ts b/packages/web-components/src/dialog/dialog.styles.ts index 99a4da18c38cc1..30da3a84b4a6b7 100644 --- a/packages/web-components/src/dialog/dialog.styles.ts +++ b/packages/web-components/src/dialog/dialog.styles.ts @@ -14,7 +14,6 @@ import { spacingHorizontalXL, spacingHorizontalXS, spacingHorizontalXXL, - spacingVerticalM, spacingVerticalS, spacingVerticalXS, spacingVerticalXXL, @@ -28,6 +27,7 @@ import { display } from '@microsoft/fast-foundation'; */ export const styles = css` ${display('flex')} + :host([hidden]) { display: none; } @@ -77,7 +77,6 @@ export const styles = css` .root { box-sizing: border-box; display: grid; - /* flex-direction: column; */ grid-template-rows: auto 1fr auto; grid-template-columns: 1fr 1fr auto; overflow: unset; @@ -126,11 +125,8 @@ export const styles = css` display: flex; flex-direction: row; padding: ${spacingVerticalS} ${spacingHorizontalXXL} ${spacingHorizontalXXL} ${spacingHorizontalXXL}; - /* justify-content: flex-end; */ - /* align-items: center; */ height: fit-content; column-gap: ${spacingHorizontalS}; - box-sizing: border-box; grid-column-start: 2; grid-row-start: 3; From 133f49b5f244511d049f1a7f169e4a1a38c346c9 Mon Sep 17 00:00:00 2001 From: brianchristopherbrady Date: Tue, 18 Jul 2023 17:04:54 -0700 Subject: [PATCH 13/45] dialog: updates styles --- packages/web-components/src/dialog/dialog.styles.ts | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/packages/web-components/src/dialog/dialog.styles.ts b/packages/web-components/src/dialog/dialog.styles.ts index 30da3a84b4a6b7..d48dca0fbd12e5 100644 --- a/packages/web-components/src/dialog/dialog.styles.ts +++ b/packages/web-components/src/dialog/dialog.styles.ts @@ -32,9 +32,6 @@ export const styles = css` display: none; } - :host { - } - .overlay { position: fixed; top: 0; @@ -156,5 +153,8 @@ export const styles = css` justify-self: stretch; width: 100%; } + ::slotted([slot='actions']) { + width: 100%; + } } `; From 7e3aeaef6adedbf317140c1eff4b36d8e3360184 Mon Sep 17 00:00:00 2001 From: brianchristopherbrady Date: Wed, 19 Jul 2023 13:50:54 -0700 Subject: [PATCH 14/45] updates docs --- packages/web-components/src/dialog/README.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/packages/web-components/src/dialog/README.md b/packages/web-components/src/dialog/README.md index 373c2f753baed8..01af471910718b 100644 --- a/packages/web-components/src/dialog/README.md +++ b/packages/web-components/src/dialog/README.md @@ -10,6 +10,8 @@ Fluent WC3 Dialog has feature parity with the Fluent UI React 9 Dialog implementation but not direct parity. +## Superclass: `FASTDialog` + ## Class: `Dialog`
From 91dd5a055af7920f6d900347ef95fc263cd2bcd0 Mon Sep 17 00:00:00 2001 From: brianchristopherbrady Date: Thu, 3 Aug 2023 12:30:24 -0700 Subject: [PATCH 15/45] deletes dead code --- packages/web-components/src/input/README.md | 135 -------------------- 1 file changed, 135 deletions(-) delete mode 100644 packages/web-components/src/input/README.md diff --git a/packages/web-components/src/input/README.md b/packages/web-components/src/input/README.md deleted file mode 100644 index 1461fca61850bc..00000000000000 --- a/packages/web-components/src/input/README.md +++ /dev/null @@ -1,135 +0,0 @@ -# TextInput - -> An implementation of a [text input](https://w3c.github.io/html-reference/input.text.html) as a form-connected web-component. - -
- -## **Design Spec** - -[Link to Text Input Design Spec in Figma](https://www.figma.com/file/TvHmWjZYxwtI9Tz6v5BT7E/Input?node-id=2366-657&t=UNSOfCD3St9ffppx-0) - -
- -## **Engineering Spec** - -Fluent WC3 Text Input extends from the [FAST Text Field](https://explore.fast.design/components/fast-text-field) and is intended to be as close to the Fluent UI React 9 Input implementation as possible. However, due to the nature of web components there will not be 100% parity between the two. - -
- -## Class: `TextInput` - -
- -### **Component Name** - -`` - -
- -### **Variables** - -| Name | Description | Type | -| ------------ | ------------------------------------ | ---------------------------------------------------------------------------------------------------------------- | -| `size` | Size variations for text input | `{ small: "small", medium: "medium", large: "large" }` | -| `appearance` | Appearance variations for text input | `{ outline: "outline", underline: "underline", filledLighter: "filled-lighter", filledDarker: "filled-darker" }` | -| `type` | Text input types | `{ email: "email", password: "password", tel: "tel", text: "text", url: "url" }` | -| `layout` | Layout variations for text input | `{ block: "block", inline: "inline"` | - -
- -### **Fields** - -| Name | Privacy | Type | Default | Description | -| --------------- | ------- | ----------------- | ----------------------- | ---------------------------------------------------------------------------------------------------------------------------------- | -| `appearance` | public | `InputAppearance` | `outline` | Sets appearance of text input. | -| `autofocus` | public | `boolean` | `false` | Indicates element should get focus after the page finishes loading.. | -| `disabled` | public | `boolean` | `false` | Disables text input | -| `labelPosition` | public | `boolean` | `false` | Disables text input | -| `layout` | public | `InputLayout` | `TextInputLayout.block` | Sets layout display property on text input | -| `list` | public | `string` | | Allows associating a `datalist` to an element by `id` | -| `maxlength` | public | `number` | | The maximum number of characters a user can enter | -| `minlength` | public | `number` | | The minimum number of characters a user can enter | -| `name` | public | `number` | | The name of the control | -| `pattern` | public | `string` | | A regular expression the text input's contents must match in order to be valid | -| `placeholder` | public | `string` | | An exemplar value to display in the text input field whenever it is empty | -| `readonly` | public | `boolean` | `false` | The text input should be submitted with the form but should not be editable | -| `required` | public | `boolean` | `false` | Sets the text input as required | -| `size` | public | `InputSize` | `medium` | Sets the size of the text input | -| `spellcheck` | public | `boolean` | `false` | Controls whether or not to enable spell checking for the text input, or if the default spell checking configuration should be used | -| `type` | public | `TextInputType` | `TextInputType.text` | Sets the size of the text input | - -
- -### **Methods** - -| Name | Privacy | Description | -| ---------- | ------- | ------------------------------------------------- | -| `select` | public | Selects all the text in the text field | -| `validate` | public | {@inheritDoc (FormAssociated:interface).validate} | - -### **Events** - -| Name | Type | Description | Inherited From | -| -------- | ---- | --------------------------- | -------------- | -| `change` | | Fires a custom change event | | - -
- -### **Attributes** - -| Name | Field | -| ---------------- | -------------- | -| `appearance` | appearance | -| `autofocus` | autofocus | -| `label-position` | label-position | -| `list` | list | -| `maxlength` | maxlength | -| `minlength` | minlength | -| `pattern` | pattern | -| `placeholder` | placeholder | -| `readonly ` | readonly | -| `size` | size | -| `spellcheck` | spellcheck | -| `type` | type | - -
- -### **Slots** - -| Name | Description | -| ------- | ---------------------------------------------------------------------------- | -| `start` | used to place content at the start of the text input within the input border | -| `end` | used to place content at the end of the text input within the input border | -| | The default slot for text input content | - -
-
-
- -## **Accessibility** - -[W3C Text Input Spec](https://w3c.github.io/html-reference/input.text.html) - -
- -### **WAI-ARIA Roles, States, and Properties** - -This component supports ARIA attributes that inherit from the [ARIA Global States and Properties](https://www.w3.org/TR/wai-aria-1.2/#global_states). - -
-
-
- -## **Preparation** - -### **Fluent Web Component v3 v.s Fluent React 9** - -
- -**Component and Slot Mapping** - -| Fluent UI React 9 | Fluent Web Components 3 | -| ----------------- | ----------------------- | -| `` | `` | -| `contentBefore` | `start` | -| `contentAfter` | `end` | From d04442e23dec1ac85e8593d7936d8ee88e030fdd Mon Sep 17 00:00:00 2001 From: brianchristopherbrady Date: Thu, 3 Aug 2023 12:52:18 -0700 Subject: [PATCH 16/45] dialog: addresses PR feedback --- .../src/dialog/dialog.stories.ts | 18 +++++++++--------- .../web-components/src/dialog/dialog.styles.ts | 6 +++--- 2 files changed, 12 insertions(+), 12 deletions(-) diff --git a/packages/web-components/src/dialog/dialog.stories.ts b/packages/web-components/src/dialog/dialog.stories.ts index 5f0fa483681efd..1e792d6659f604 100644 --- a/packages/web-components/src/dialog/dialog.stories.ts +++ b/packages/web-components/src/dialog/dialog.stories.ts @@ -43,18 +43,18 @@ const dialogTemplate = html`
openDialog(e, 'dialog-default')}>Open Dialog - x.modal} - ?alert=${x => x.alert} - ?no-trap-focus=${x => x.noFocusTrap} + x.modal} + ?alert=${x => x.alert} + ?no-trap-focus=${x => x.noFocusTrap} hidden >
Dialog Title
Dialog is a window overlaid on either the primary window or another dialog window. Windows under a modal dialog are inert. That is, users cannot interact with content outside an active dialog window. Inert content outside an active dialog is typically visually obscured or dimmed so it is difficult to discern, and in some implementations, attempts to interact with the inert content cause the dialog to close.
- Close Drawer Do Something @@ -73,7 +73,7 @@ export default { }, argTypes: { hidden: { - description: 'Renders dialog as a modal', + description: 'Sets the visibility of the dialog', table: { defaultValue: { summary: false, diff --git a/packages/web-components/src/dialog/dialog.styles.ts b/packages/web-components/src/dialog/dialog.styles.ts index d48dca0fbd12e5..bb5d4367d5d698 100644 --- a/packages/web-components/src/dialog/dialog.styles.ts +++ b/packages/web-components/src/dialog/dialog.styles.ts @@ -129,8 +129,8 @@ export const styles = css` grid-row-start: 3; justify-self: end; grid-column-end: 4; - row-gap: 8px; - column-gap: 8px; + row-gap: ${spacingHorizontalS}; + column-gap: ${spacingVerticalS}; grid-template-columns: 1fr 1fr auto; grid-template-rows: auto 1fr auto; } @@ -138,7 +138,7 @@ export const styles = css` @media screen and (max-width: 480px) { .control { max-width: 100%; - width: 100vh; + width: 100vw; } .root { max-width: 100vw; From 514f6b6b348e5ce29ed1734d19c27a9fa6c33686 Mon Sep 17 00:00:00 2001 From: brianchristopherbrady Date: Thu, 3 Aug 2023 14:02:27 -0700 Subject: [PATCH 17/45] reverts dead file --- packages/web-components/src/input/README.md | 135 -------------------- 1 file changed, 135 deletions(-) delete mode 100644 packages/web-components/src/input/README.md diff --git a/packages/web-components/src/input/README.md b/packages/web-components/src/input/README.md deleted file mode 100644 index 1461fca61850bc..00000000000000 --- a/packages/web-components/src/input/README.md +++ /dev/null @@ -1,135 +0,0 @@ -# TextInput - -> An implementation of a [text input](https://w3c.github.io/html-reference/input.text.html) as a form-connected web-component. - -
- -## **Design Spec** - -[Link to Text Input Design Spec in Figma](https://www.figma.com/file/TvHmWjZYxwtI9Tz6v5BT7E/Input?node-id=2366-657&t=UNSOfCD3St9ffppx-0) - -
- -## **Engineering Spec** - -Fluent WC3 Text Input extends from the [FAST Text Field](https://explore.fast.design/components/fast-text-field) and is intended to be as close to the Fluent UI React 9 Input implementation as possible. However, due to the nature of web components there will not be 100% parity between the two. - -
- -## Class: `TextInput` - -
- -### **Component Name** - -`` - -
- -### **Variables** - -| Name | Description | Type | -| ------------ | ------------------------------------ | ---------------------------------------------------------------------------------------------------------------- | -| `size` | Size variations for text input | `{ small: "small", medium: "medium", large: "large" }` | -| `appearance` | Appearance variations for text input | `{ outline: "outline", underline: "underline", filledLighter: "filled-lighter", filledDarker: "filled-darker" }` | -| `type` | Text input types | `{ email: "email", password: "password", tel: "tel", text: "text", url: "url" }` | -| `layout` | Layout variations for text input | `{ block: "block", inline: "inline"` | - -
- -### **Fields** - -| Name | Privacy | Type | Default | Description | -| --------------- | ------- | ----------------- | ----------------------- | ---------------------------------------------------------------------------------------------------------------------------------- | -| `appearance` | public | `InputAppearance` | `outline` | Sets appearance of text input. | -| `autofocus` | public | `boolean` | `false` | Indicates element should get focus after the page finishes loading.. | -| `disabled` | public | `boolean` | `false` | Disables text input | -| `labelPosition` | public | `boolean` | `false` | Disables text input | -| `layout` | public | `InputLayout` | `TextInputLayout.block` | Sets layout display property on text input | -| `list` | public | `string` | | Allows associating a `datalist` to an element by `id` | -| `maxlength` | public | `number` | | The maximum number of characters a user can enter | -| `minlength` | public | `number` | | The minimum number of characters a user can enter | -| `name` | public | `number` | | The name of the control | -| `pattern` | public | `string` | | A regular expression the text input's contents must match in order to be valid | -| `placeholder` | public | `string` | | An exemplar value to display in the text input field whenever it is empty | -| `readonly` | public | `boolean` | `false` | The text input should be submitted with the form but should not be editable | -| `required` | public | `boolean` | `false` | Sets the text input as required | -| `size` | public | `InputSize` | `medium` | Sets the size of the text input | -| `spellcheck` | public | `boolean` | `false` | Controls whether or not to enable spell checking for the text input, or if the default spell checking configuration should be used | -| `type` | public | `TextInputType` | `TextInputType.text` | Sets the size of the text input | - -
- -### **Methods** - -| Name | Privacy | Description | -| ---------- | ------- | ------------------------------------------------- | -| `select` | public | Selects all the text in the text field | -| `validate` | public | {@inheritDoc (FormAssociated:interface).validate} | - -### **Events** - -| Name | Type | Description | Inherited From | -| -------- | ---- | --------------------------- | -------------- | -| `change` | | Fires a custom change event | | - -
- -### **Attributes** - -| Name | Field | -| ---------------- | -------------- | -| `appearance` | appearance | -| `autofocus` | autofocus | -| `label-position` | label-position | -| `list` | list | -| `maxlength` | maxlength | -| `minlength` | minlength | -| `pattern` | pattern | -| `placeholder` | placeholder | -| `readonly ` | readonly | -| `size` | size | -| `spellcheck` | spellcheck | -| `type` | type | - -
- -### **Slots** - -| Name | Description | -| ------- | ---------------------------------------------------------------------------- | -| `start` | used to place content at the start of the text input within the input border | -| `end` | used to place content at the end of the text input within the input border | -| | The default slot for text input content | - -
-
-
- -## **Accessibility** - -[W3C Text Input Spec](https://w3c.github.io/html-reference/input.text.html) - -
- -### **WAI-ARIA Roles, States, and Properties** - -This component supports ARIA attributes that inherit from the [ARIA Global States and Properties](https://www.w3.org/TR/wai-aria-1.2/#global_states). - -
-
-
- -## **Preparation** - -### **Fluent Web Component v3 v.s Fluent React 9** - -
- -**Component and Slot Mapping** - -| Fluent UI React 9 | Fluent Web Components 3 | -| ----------------- | ----------------------- | -| `` | `` | -| `contentBefore` | `start` | -| `contentAfter` | `end` | From 8359b575fe5b1ee91edf7a8c40e85ca91c88f902 Mon Sep 17 00:00:00 2001 From: brianchristopherbrady Date: Mon, 21 Aug 2023 14:29:08 -0700 Subject: [PATCH 18/45] dialog: updates styles per feedback --- .../src/dialog/dialog.styles.ts | 38 ++++++++++++------- 1 file changed, 25 insertions(+), 13 deletions(-) diff --git a/packages/web-components/src/dialog/dialog.styles.ts b/packages/web-components/src/dialog/dialog.styles.ts index bb5d4367d5d698..937e99ded268d6 100644 --- a/packages/web-components/src/dialog/dialog.styles.ts +++ b/packages/web-components/src/dialog/dialog.styles.ts @@ -1,14 +1,16 @@ import { borderRadiusXLarge, + colorBackgroundOverlay, colorNeutralBackground1, + colorNeutralForeground1, colorTransparentStroke, fontFamilyBase, fontSizeBase300, - fontSizeBase400, + fontSizeBase500, fontWeightRegular, fontWeightSemibold, lineHeightBase300, - lineHeightBase400, + lineHeightBase500, shadow64, spacingHorizontalS, spacingHorizontalXL, @@ -38,7 +40,7 @@ export const styles = css` left: 0; right: 0; bottom: 0; - background: rgba(0, 0, 0, 0.3); + background: ${colorBackgroundOverlay}; touch-action: none; } @@ -75,21 +77,33 @@ export const styles = css` box-sizing: border-box; display: grid; grid-template-rows: auto 1fr auto; - grid-template-columns: 1fr 1fr auto; + grid-template-columns: auto 1fr 76px; overflow: unset; max-height: calc(100vh - 48px); } + :host([alert]) .root, + :host([modal]) .root { + grid-template-columns: auto 1fr; + } + + :host([alert]) .header, + :host([modal]) .header { + padding-right: ${spacingVerticalXXL}; + } + .header { - grid-column-start: 1; - grid-row-end: 1; - grid-row-start: 1; + grid-column: 1 / 3; + grid-row: 1 / 1; padding-bottom: ${spacingVerticalXS}; - font-size: ${fontSizeBase400}; - line-height: ${lineHeightBase400}; + font-size: ${fontSizeBase500}; + line-height: ${lineHeightBase500}; font-weight: ${fontWeightSemibold}; font-family: ${fontFamilyBase}; padding: ${spacingVerticalXXL} ${spacingHorizontalXS} ${spacingVerticalXS} ${spacingHorizontalXXL}; + color: ${colorNeutralForeground1}; + margin-bottom: ${spacingVerticalS}; + display: inline-block; height: fit-content; } @@ -110,6 +124,7 @@ export const styles = css` padding: 0 ${spacingHorizontalXXL}; vertical-align: top; min-height: 32px; + color: ${colorNeutralForeground1}; font-size: ${fontSizeBase300}; line-height: ${lineHeightBase300}; font-weight: ${fontWeightRegular}; @@ -140,10 +155,7 @@ export const styles = css` max-width: 100%; width: 100vw; } - .root { - max-width: 100vw; - grid-template-rows: auto 1fr auto; - } + .actions { display: flex; grid-column-start: 1; From b7d6c59c7040bf2e5d4f38ef39e038d9470bea36 Mon Sep 17 00:00:00 2001 From: brianchristopherbrady Date: Tue, 19 Sep 2023 15:03:38 -0700 Subject: [PATCH 19/45] drawer: updates template, styles --- .../src/dialog/dialog.stories.ts | 136 ++++++++++-------- .../src/dialog/dialog.styles.ts | 49 ++----- .../src/dialog/dialog.template.ts | 80 ++++------- 3 files changed, 123 insertions(+), 142 deletions(-) diff --git a/packages/web-components/src/dialog/dialog.stories.ts b/packages/web-components/src/dialog/dialog.stories.ts index 1e792d6659f604..36286715b5c18b 100644 --- a/packages/web-components/src/dialog/dialog.stories.ts +++ b/packages/web-components/src/dialog/dialog.stories.ts @@ -9,17 +9,17 @@ import '../text/define.js'; type DialogStoryArgs = Args & FluentDialog; type DialogStoryMeta = Meta; -const DismissCircle24Regular = html` +const dismissed16Regular = html` @@ -42,24 +42,36 @@ const dialogTemplate = html` }
- openDialog(e, 'dialog-default')}>Open Dialog - x.modal} - ?alert=${x => x.alert} - ?no-trap-focus=${x => x.noFocusTrap} - hidden + openDialog(e, 'dialog-default')}>Open Dialog + x.modal} + ?alert=${x => x.alert} + ?no-focus-trap=${x => x.noFocusTrap} + hidden + > + Dialog + + ${dismissed16Regular} + + +

+ The Dialog component is a window overlaid on either the primary window or another dialog window. Windows under + a modal dialog are inert. That is, users cannot interact with content outside an active dialog window. +

+
+
+ fluent-dialog + Close Drawer -
Dialog Title
-
Dialog is a window overlaid on either the primary window or another dialog window. Windows under a modal dialog are inert. That is, users cannot interact with content outside an active dialog window. Inert content outside an active dialog is typically visually obscured or dimmed so it is difficult to discern, and in some implementations, attempts to interact with the inert content cause the dialog to close.
- Close Drawer - Do Something -
-
+ Do Something +
`; @@ -69,7 +81,7 @@ export default { modal: false, alert: false, hidden: false, - noTrapFocus: false, + noFocusTrap: false, }, argTypes: { hidden: { @@ -117,15 +129,18 @@ export const Modal = renderComponent(html`
openDialog(e, 'dialog-modal')}>Open Dialog
`); @@ -134,16 +149,17 @@ export const Alert = renderComponent(html`
openDialog(e, 'dialog-alert')}>Open Dialog
`); @@ -152,8 +168,15 @@ export const ScrollingLongContent = renderComponent(html`
openDialog(e, 'dialog-longcontent')}>Open Dialog -
-`); - -export const CustomCloseIcon = renderComponent(html` -
- openDialog(e, 'dialog-closeicon')}>Open Dialog -
`); @@ -225,15 +233,29 @@ export const NoFocusTrap = renderComponent(html`
openDialog(e, 'dialog-nofocustrap')}>Open Dialog
`); diff --git a/packages/web-components/src/dialog/dialog.styles.ts b/packages/web-components/src/dialog/dialog.styles.ts index 937e99ded268d6..7be017d033e9bc 100644 --- a/packages/web-components/src/dialog/dialog.styles.ts +++ b/packages/web-components/src/dialog/dialog.styles.ts @@ -13,11 +13,8 @@ import { lineHeightBase500, shadow64, spacingHorizontalS, - spacingHorizontalXL, - spacingHorizontalXS, spacingHorizontalXXL, spacingVerticalS, - spacingVerticalXS, spacingVerticalXXL, strokeWidthThin, } from '@fluentui/web-components'; @@ -52,6 +49,7 @@ export const styles = css` bottom: 0; left: 0; right: 0; + z-index: var(--dialog-elevation, 9999); } .control { @@ -75,11 +73,12 @@ export const styles = css` .root { box-sizing: border-box; - display: grid; - grid-template-rows: auto 1fr auto; - grid-template-columns: auto 1fr 76px; + display: flex; + row-gap: 8px; + flex-direction: column; overflow: unset; max-height: calc(100vh - 48px); + padding: ${spacingVerticalXXL} ${spacingHorizontalXXL}; } :host([alert]) .root, @@ -93,35 +92,20 @@ export const styles = css` } .header { - grid-column: 1 / 3; - grid-row: 1 / 1; - padding-bottom: ${spacingVerticalXS}; font-size: ${fontSizeBase500}; line-height: ${lineHeightBase500}; font-weight: ${fontWeightSemibold}; font-family: ${fontFamilyBase}; - padding: ${spacingVerticalXXL} ${spacingHorizontalXS} ${spacingVerticalXS} ${spacingHorizontalXXL}; color: ${colorNeutralForeground1}; margin-bottom: ${spacingVerticalS}; - display: inline-block; height: fit-content; - } - - .close { - align-self: start; - justify-self: end; - grid-column-start: 3; - grid-row-end: 1; - grid-row-start: 1; - padding: ${spacingVerticalXXL} ${spacingHorizontalXL} ${spacingVerticalS} ${spacingHorizontalXXL}; + display: flex; + justify-content: space-between; + align-items: flex-start; + column-gap: 8px; } .content { - grid-row-end: 2; - grid-row-start: 2; - grid-column-start: 1; - grid-column-end: 4; - padding: 0 ${spacingHorizontalXXL}; vertical-align: top; min-height: 32px; color: ${colorNeutralForeground1}; @@ -133,21 +117,16 @@ export const styles = css` box-sizing: border-box; } - .actions { + .footer { display: flex; flex-direction: row; - padding: ${spacingVerticalS} ${spacingHorizontalXXL} ${spacingHorizontalXXL} ${spacingHorizontalXXL}; + justify-content: flex-end; + align-items: center; height: fit-content; column-gap: ${spacingHorizontalS}; box-sizing: border-box; - grid-column-start: 2; - grid-row-start: 3; - justify-self: end; - grid-column-end: 4; row-gap: ${spacingHorizontalS}; column-gap: ${spacingVerticalS}; - grid-template-columns: 1fr 1fr auto; - grid-template-rows: auto 1fr auto; } @media screen and (max-width: 480px) { @@ -156,7 +135,7 @@ export const styles = css` width: 100vw; } - .actions { + .footer { display: flex; grid-column-start: 1; flex-direction: column; @@ -165,7 +144,7 @@ export const styles = css` justify-self: stretch; width: 100%; } - ::slotted([slot='actions']) { + ::slotted([slot='footer']) { width: 100%; } } diff --git a/packages/web-components/src/dialog/dialog.template.ts b/packages/web-components/src/dialog/dialog.template.ts index 3c8d42010116fb..2554247c374d92 100644 --- a/packages/web-components/src/dialog/dialog.template.ts +++ b/packages/web-components/src/dialog/dialog.template.ts @@ -1,60 +1,40 @@ import { ElementViewTemplate, html, ref, when } from '@microsoft/fast-element'; import type { Dialog } from './dialog.js'; -const dismissed16Regular = html` - -`; - /** * Template for the Dialog component * @public */ -export const template: ElementViewTemplate = html`
- ${when( - x => x.modal || x.alert, - html` `, - )} -
From 51e5374aa8fc2f23d0ba976c199efa05af111742 Mon Sep 17 00:00:00 2001 From: brianchristopherbrady Date: Mon, 2 Oct 2023 16:43:55 -0700 Subject: [PATCH 22/45] yarn change --- ...eb-components-c3eff1b3-5486-4127-9d4b-c9d6d05fdb24.json | 7 +++++++ 1 file changed, 7 insertions(+) create mode 100644 change/@fluentui-web-components-c3eff1b3-5486-4127-9d4b-c9d6d05fdb24.json diff --git a/change/@fluentui-web-components-c3eff1b3-5486-4127-9d4b-c9d6d05fdb24.json b/change/@fluentui-web-components-c3eff1b3-5486-4127-9d4b-c9d6d05fdb24.json new file mode 100644 index 00000000000000..f15f2159a265d6 --- /dev/null +++ b/change/@fluentui-web-components-c3eff1b3-5486-4127-9d4b-c9d6d05fdb24.json @@ -0,0 +1,7 @@ +{ + "type": "prerelease", + "comment": "feat(dialog): add dialog web component", + "packageName": "@fluentui/web-components", + "email": "brian.christopher.brady@gmail.com", + "dependentChangeType": "patch" +} From 113a05e32d350912908ad67f5206c4392513b104 Mon Sep 17 00:00:00 2001 From: brianchristopherbrady Date: Mon, 2 Oct 2023 17:07:55 -0700 Subject: [PATCH 23/45] dialog: addresses feedback --- packages/web-components/src/dialog/README.md | 65 ++++++------------- .../src/dialog/dialog.styles.ts | 16 +---- 2 files changed, 24 insertions(+), 57 deletions(-) diff --git a/packages/web-components/src/dialog/README.md b/packages/web-components/src/dialog/README.md index 810d47458bc6f1..27d6c9b446029b 100644 --- a/packages/web-components/src/dialog/README.md +++ b/packages/web-components/src/dialog/README.md @@ -10,7 +10,7 @@ Fluent WC3 Dialog has feature parity with the Fluent UI React 9 Dialog implementation but not direct parity. -## Superclass: `FASTDialog` +## Superclass: [FASTDialog](https://github.com/microsoft/fast/tree/master/packages/web-components/fast-foundation/src/dialog) ## Class: `Dialog` @@ -20,42 +20,19 @@ Fluent WC3 Dialog has feature parity with the Fluent UI React 9 Dialog implement `` -### **Template** - -```ts -export const template: ElementViewTemplate = html` -
- ${when( - x => x.modal || x.alert, - html` `, - )} -
-
-
- - -
- -
- -
- -
-
-
-`; +### **Basic Implemenation** + +```html + + + Dialog + + + Content + + + Do Something + ``` ### **Attributes** @@ -85,12 +62,12 @@ export const template: ElementViewTemplate = html` ### **Slots** -| Name | Description | -| --------- | ------------------------ | -| `title` | slot for title content | -| `close` | slot for close button | -| | default slot for content | -| `actions` | slot for actions content | +| Name | Description | +| --------- | ---------------------------------------------------------- | +| `title` | slot for title content | +| `close` | slot for close button | +| | default slot for content rendered between title and footer | +| `actions` | slot for actions content | ### **CSS Variables** @@ -108,7 +85,7 @@ export const template: ElementViewTemplate = html` | ----------------- | ------------------------ | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `` | `` | tag name | | `` | methods: `hide() show()` | In the React version of our components, a "DialogTrigger" component is utilized as part of a composite component of Dialog. The DialogTrigger component provides functionality for toggling the visibility of the Dialog component.
In the Web Component version does not include a dialog trigger. Instead, it expects the user to directly access methods on the Dialog class or utilize CSS to control the visibility of the dialog component. | -| `` | `.overlay` | In the React version of our components, the DialogSurface component is used as part of the composite Dialog component to represent the dimmed background of the dialog.
In the Web Component version utilizes an HTML element with a class of ".overlay" as part of the Dialog component to achieve the same effect of a dimmed background for the dialog. | +| `` | `.overlay` | In the React version of our components, the DialogSurface component is used as part of the composite Dialog component to represent the dimmed background of the dialog.
The Web Component version utilizes an HTML element with a class of ".overlay" as part of the Dialog component to achieve the same effect of a dimmed background for the dialog. | | `` | `slot: title` | In the React version of our components, the component is used to implement the title of the dialog.
In the Web Component version, the title is provided through the title slot. | | `` | `slot: actions ` | In the React version of our components, the component is used to implement the actions within the dialog.
In the Web Component version, actions are passsed through the `actions` slot | diff --git a/packages/web-components/src/dialog/dialog.styles.ts b/packages/web-components/src/dialog/dialog.styles.ts index 7be017d033e9bc..596181ff0ae5b2 100644 --- a/packages/web-components/src/dialog/dialog.styles.ts +++ b/packages/web-components/src/dialog/dialog.styles.ts @@ -33,10 +33,7 @@ export const styles = css` .overlay { position: fixed; - top: 0; - left: 0; - right: 0; - bottom: 0; + inset: 0; background: ${colorBackgroundOverlay}; touch-action: none; } @@ -45,10 +42,7 @@ export const styles = css` display: flex; justify-content: center; position: fixed; - top: 0; - bottom: 0; - left: 0; - right: 0; + inset: 0; z-index: var(--dialog-elevation, 9999); } @@ -65,10 +59,7 @@ export const styles = css` height: fit-content; overflow: unset; position: fixed; - top: 0; - bottom: 0; - left: 0; - right: 0; + inset: 0; } .root { @@ -98,7 +89,6 @@ export const styles = css` font-family: ${fontFamilyBase}; color: ${colorNeutralForeground1}; margin-bottom: ${spacingVerticalS}; - height: fit-content; display: flex; justify-content: space-between; align-items: flex-start; From ccfde13d9eebadb853ad3cadc1dba189e39bbdd2 Mon Sep 17 00:00:00 2001 From: brianchristopherbrady Date: Tue, 3 Oct 2023 10:26:58 -0700 Subject: [PATCH 24/45] dialog: updates README --- packages/web-components/src/dialog/README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/web-components/src/dialog/README.md b/packages/web-components/src/dialog/README.md index 27d6c9b446029b..b1d25ef9cda0e0 100644 --- a/packages/web-components/src/dialog/README.md +++ b/packages/web-components/src/dialog/README.md @@ -23,7 +23,7 @@ Fluent WC3 Dialog has feature parity with the Fluent UI React 9 Dialog implement ### **Basic Implemenation** ```html - + Dialog @@ -32,7 +32,7 @@ Fluent WC3 Dialog has feature parity with the Fluent UI React 9 Dialog implement Do Something - +
``` ### **Attributes** From f5659df2c3853c6bcbb9ec0c972d9e993dc8c1cb Mon Sep 17 00:00:00 2001 From: brianchristopherbrady Date: Tue, 3 Oct 2023 11:09:12 -0700 Subject: [PATCH 25/45] dialog: fixes responsive styles --- .../src/dialog/dialog.styles.ts | 50 ++++++++++--------- 1 file changed, 27 insertions(+), 23 deletions(-) diff --git a/packages/web-components/src/dialog/dialog.styles.ts b/packages/web-components/src/dialog/dialog.styles.ts index 596181ff0ae5b2..9ad430f14c2220 100644 --- a/packages/web-components/src/dialog/dialog.styles.ts +++ b/packages/web-components/src/dialog/dialog.styles.ts @@ -51,8 +51,8 @@ export const styles = css` border: ${strokeWidthThin} solid ${colorTransparentStroke}; z-index: 2; margin: auto auto; - width: 100%; - max-width: 600px; + max-width: 100%; + width: 100vw; border-radius: ${borderRadiusXLarge}; box-shadow: ${shadow64}; max-height: 100vh; @@ -109,33 +109,37 @@ export const styles = css` .footer { display: flex; - flex-direction: row; - justify-content: flex-end; - align-items: center; - height: fit-content; - column-gap: ${spacingHorizontalS}; - box-sizing: border-box; - row-gap: ${spacingHorizontalS}; - column-gap: ${spacingVerticalS}; + grid-column-start: 1; + flex-direction: column; + max-width: 100vw; + padding-top: ${spacingVerticalXXL}; + justify-self: stretch; + width: 100%; + row-gap: ${spacingVerticalS}; + } + + ::slotted([slot='actions']) { + width: 100%; } - @media screen and (max-width: 480px) { + @media screen and (min-width: 480px) { + ::slotted([slot='actions']) { + width: fit-content; + } .control { - max-width: 100%; - width: 100vw; + max-width: 600px; + width: 100%; } - .footer { display: flex; - grid-column-start: 1; - flex-direction: column; - max-width: 100vw; - padding-top: ${spacingVerticalXXL}; - justify-self: stretch; - width: 100%; - } - ::slotted([slot='footer']) { - width: 100%; + flex-direction: row; + justify-content: flex-end; + align-items: center; + height: fit-content; + column-gap: ${spacingHorizontalS}; + box-sizing: border-box; + row-gap: ${spacingHorizontalS}; + column-gap: ${spacingVerticalS}; } } `; From a41f491b9ed7aecdbe87f84a9453d7c2e621fa75 Mon Sep 17 00:00:00 2001 From: brianchristopherbrady Date: Tue, 10 Oct 2023 14:48:08 -0700 Subject: [PATCH 26/45] dialog: removes dead styles --- packages/web-components/src/dialog/dialog.stories.ts | 8 -------- packages/web-components/src/dialog/dialog.styles.ts | 10 ---------- 2 files changed, 18 deletions(-) diff --git a/packages/web-components/src/dialog/dialog.stories.ts b/packages/web-components/src/dialog/dialog.stories.ts index e7ecfa1a315cb9..8d34d473130a97 100644 --- a/packages/web-components/src/dialog/dialog.stories.ts +++ b/packages/web-components/src/dialog/dialog.stories.ts @@ -46,14 +46,6 @@ const dialogTemplate = html` hidden > Dialog - - ${dismissed16Regular} -

The Dialog component is a window overlaid on either the primary window or another dialog window. Windows under diff --git a/packages/web-components/src/dialog/dialog.styles.ts b/packages/web-components/src/dialog/dialog.styles.ts index 9ad430f14c2220..52f35d1af460ae 100644 --- a/packages/web-components/src/dialog/dialog.styles.ts +++ b/packages/web-components/src/dialog/dialog.styles.ts @@ -72,16 +72,6 @@ export const styles = css` padding: ${spacingVerticalXXL} ${spacingHorizontalXXL}; } - :host([alert]) .root, - :host([modal]) .root { - grid-template-columns: auto 1fr; - } - - :host([alert]) .header, - :host([modal]) .header { - padding-right: ${spacingVerticalXXL}; - } - .header { font-size: ${fontSizeBase500}; line-height: ${lineHeightBase500}; From 25262723ccbfd16324523558fd5f6ee09143edbc Mon Sep 17 00:00:00 2001 From: brianchristopherbrady Date: Tue, 10 Oct 2023 14:49:11 -0700 Subject: [PATCH 27/45] dialog: updates readme docs --- packages/web-components/src/dialog/README.md | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/packages/web-components/src/dialog/README.md b/packages/web-components/src/dialog/README.md index b1d25ef9cda0e0..f48917477fee8a 100644 --- a/packages/web-components/src/dialog/README.md +++ b/packages/web-components/src/dialog/README.md @@ -37,15 +37,15 @@ Fluent WC3 Dialog has feature parity with the Fluent UI React 9 Dialog implement ### **Attributes** -| Name | Privacy | Type | Default | Description | -| ------------------ | ------- | --------- | ------- | ------------------------------------------------ | -| `modal` | public | `boolean` | `false` | Renders dialog as a modal | -| `alert` | public | `boolean` | `false` | Renders dialog as an alert modal | -| `hidden` | public | `boolean` | `false` | Sets the visibility of the dialog | -| `no-focus-trap` | public | `boolean` | `false` | Indicates that the dialog should not trap focus. | -| `aria-labelledby` | public | `boolean` | `false` | optional based on implementation\*\* | -| `aria-describedby` | public | `boolean` | `false` | optional based on implementation\*\* | -| `aria-label ` | public | `boolean` | `false` | optional based on implementation\*\* | +| Name | Privacy | Type | Default | Description | +| ------------------ | ------- | --------- | ------- | ------------------------------------------------------------------------------------------------------------- | +| `modal` | public | `boolean` | `false` | Renders dialog as a modal | +| `alert` | public | `boolean` | `false` | Renders dialog as an alert modal, alert modals will not close on escape keypress or by onclick of the overlay | +| `hidden` | public | `boolean` | `false` | Sets the visibility of the dialog | +| `no-focus-trap` | public | `boolean` | `false` | Indicates that the dialog should not trap focus. | +| `aria-labelledby` | public | `boolean` | `false` | optional based on implementation\*\* | +| `aria-describedby` | public | `boolean` | `false` | optional based on implementation\*\* | +| `aria-label ` | public | `boolean` | `false` | optional based on implementation\*\* | \*\* See the [W3C Specification](https://w3c.github.io/aria-practices/#dialog_roles_states_props) for requirements and details. From 7a8246ce44f86dcc7f8992fcbb895e911d449813 Mon Sep 17 00:00:00 2001 From: brianchristopherbrady Date: Thu, 12 Oct 2023 17:20:15 -0700 Subject: [PATCH 28/45] dialog: reworks dialog to use navtive html dialog element --- packages/web-components/src/dialog/README.md | 52 +-- .../src/dialog/dialog.options.ts | 13 + .../src/dialog/dialog.stories.ts | 432 ++++++++++++++---- .../src/dialog/dialog.styles.ts | 25 +- .../src/dialog/dialog.template.ts | 87 ++-- packages/web-components/src/dialog/dialog.ts | 416 ++++++++++++++++- 6 files changed, 847 insertions(+), 178 deletions(-) create mode 100644 packages/web-components/src/dialog/dialog.options.ts diff --git a/packages/web-components/src/dialog/README.md b/packages/web-components/src/dialog/README.md index f48917477fee8a..8fc382172b85ed 100644 --- a/packages/web-components/src/dialog/README.md +++ b/packages/web-components/src/dialog/README.md @@ -37,15 +37,14 @@ Fluent WC3 Dialog has feature parity with the Fluent UI React 9 Dialog implement ### **Attributes** -| Name | Privacy | Type | Default | Description | -| ------------------ | ------- | --------- | ------- | ------------------------------------------------------------------------------------------------------------- | -| `modal` | public | `boolean` | `false` | Renders dialog as a modal | -| `alert` | public | `boolean` | `false` | Renders dialog as an alert modal, alert modals will not close on escape keypress or by onclick of the overlay | -| `hidden` | public | `boolean` | `false` | Sets the visibility of the dialog | -| `no-focus-trap` | public | `boolean` | `false` | Indicates that the dialog should not trap focus. | -| `aria-labelledby` | public | `boolean` | `false` | optional based on implementation\*\* | -| `aria-describedby` | public | `boolean` | `false` | optional based on implementation\*\* | -| `aria-label ` | public | `boolean` | `false` | optional based on implementation\*\* | +| Name | Privacy | Type | Default | Description | +| ------------------ | ------- | ----------------- | ----------------------- | --------------------------------------------------------- | +| `modal-type` | public | `DialogModalType` | `DialogModalType.modal` | Indicates that the type of modal to render. | +| `change-focus` | public | `string` | `undefined` | Used to set id of desired focus target. | +| `no-title-action` | public | `boolean` | `false` | Used to set whether the default title action is rendered. | +| `aria-labelledby` | public | `boolean` | `false` | optional based on implementation\*\* | +| `aria-describedby` | public | `boolean` | `false` | optional based on implementation\*\* | +| `aria-label ` | public | `boolean` | `false` | optional based on implementation\*\* | \*\* See the [W3C Specification](https://w3c.github.io/aria-practices/#dialog_roles_states_props) for requirements and details. @@ -69,6 +68,12 @@ Fluent WC3 Dialog has feature parity with the Fluent UI React 9 Dialog implement | | default slot for content rendered between title and footer | | `actions` | slot for actions content | +### **Events** + +| Name | Description | +| -------------- | --------------------------------------------------------------- | +| `onOpenChange` | Event fired when the component transitions from its open state. | + ### **CSS Variables** | Name | Description | @@ -81,26 +86,19 @@ Fluent WC3 Dialog has feature parity with the Fluent UI React 9 Dialog implement **Component, Element, and Slot Mapping** -| Fluent UI React 9 | Fluent Web Components 3 | Description of difference | -| ----------------- | ------------------------ | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -| `

` | `` | tag name | -| `` | methods: `hide() show()` | In the React version of our components, a "DialogTrigger" component is utilized as part of a composite component of Dialog. The DialogTrigger component provides functionality for toggling the visibility of the Dialog component.
In the Web Component version does not include a dialog trigger. Instead, it expects the user to directly access methods on the Dialog class or utilize CSS to control the visibility of the dialog component. | -| `` | `.overlay` | In the React version of our components, the DialogSurface component is used as part of the composite Dialog component to represent the dimmed background of the dialog.
The Web Component version utilizes an HTML element with a class of ".overlay" as part of the Dialog component to achieve the same effect of a dimmed background for the dialog. | -| `` | `slot: title` | In the React version of our components, the component is used to implement the title of the dialog.
In the Web Component version, the title is provided through the title slot. | -| `` | `slot: actions ` | In the React version of our components, the component is used to implement the actions within the dialog.
In the Web Component version, actions are passsed through the `actions` slot | +| Fluent UI React 9 | Fluent Web Components 3 | Description of difference | +| ------------------------- | ------------------------ | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| `` | `` | tag name | +| `` | methods: `hide() show()` | In the React version of our components, a "DialogTrigger" component is utilized as part of a composite component of Dialog. The DialogTrigger component provides functionality for toggling the visibility of the Dialog component.
In the Web Component version does not include a dialog trigger. Instead, it expects the user to directly access methods on the Dialog class or utilize CSS to control the visibility of the dialog component. | +| `` | `.overlay` | In the React version of our components, the DialogSurface component is used as part of the composite Dialog component to represent the dimmed background of the dialog.
The Web Component version utilizes the HTML dialog ::backdrop pseudoelement. | +| `` | `slot: title` | In the React version of our components, the component is used to implement the title of the dialog.
In the Web Component version, the title is provided through the title slot. | +| `` | `slot: title-actions` | In the React version of our components, the component the DialogTitles action prop.
In the Web Component version, the title action is provided through the Dialogs title-action slot | +| `` | `slot: actions ` | In the React version of our components, the component is used to implement the actions within the dialog.
In the Web Component version, actions are passsed through the `actions` slot |
**Attribute and prop Mapping** -| Fluent UI React 9 | Fluent Web Components 3 | Description of difference | -| ---------------------------------------------- | ---------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | -| `open: boolean'` | `hidden: boolean` | In FUIR9, to indicate that the dialog is visible the open prop is used. In FUIWC3 the boolean hidden attribute is used. | -| `modalType: 'alert' \| 'modal' \| 'non-modal'` | `alert: boolean`, `modal: boolean` | In FUIR9, the modalType prop accepts a string value ('alert', 'modal', or 'non-modal') to specify the modal behavior. In FUIWC3, separate boolean props (alert and modal) are used to indicate whether the component should behave as an alert or a modal. | -| `onOpenChange` | `onHiddenChange` | In FUIR9, the onOpenChange event is emitted when the open prop of a component changes, indicating a change in the component's open state. FUIWC3, the onHiddenChange event is emitted when the hidden property or attribute of a component changes, indicating a change in the component's visibility state. | - -**Event Mapping** - -| Fluent UI React 9 | Fluent Web Components 3 | Description of difference | -| ----------------- | ------------------------------------ | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -| `onOpenChange` | events: `close`, `dismiss`, `cancel` | In FUIR9, the onOpenChange event is emitted when the open prop of a component changes, indicating a change in the component's open state. FUIWC3, an event is emitted to indicate the dialog has been closed or dismissed. | +| Fluent UI React 9 | Fluent Web Components 3 | Description of difference | +| ------------------------------------ | ----------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------- | +| use effect to customize focus target | `change-focus` | Changing the default focused element can be done in an effect. In FUIWC3, the id of the desired target to focus can be passed through the change-focus slot | diff --git a/packages/web-components/src/dialog/dialog.options.ts b/packages/web-components/src/dialog/dialog.options.ts new file mode 100644 index 00000000000000..7bbc17f93aa8b8 --- /dev/null +++ b/packages/web-components/src/dialog/dialog.options.ts @@ -0,0 +1,13 @@ +import type { ValuesOf } from '@microsoft/fast-foundation/utilities.js'; + +/** + * Checkbox shape + * @public + */ +export const DialogModalType = { + modal: 'modal', + nonModal: 'non-modal', + alert: 'alert', +} as const; + +export type DialogModalType = ValuesOf; diff --git a/packages/web-components/src/dialog/dialog.stories.ts b/packages/web-components/src/dialog/dialog.stories.ts index 8d34d473130a97..6383c26adef736 100644 --- a/packages/web-components/src/dialog/dialog.stories.ts +++ b/packages/web-components/src/dialog/dialog.stories.ts @@ -5,19 +5,13 @@ import type { Dialog as FluentDialog } from './dialog.js'; import './define.js'; import '../button/define.js'; import '../text/define.js'; +import { DialogModalType } from './dialog.options.js'; type DialogStoryArgs = Args & FluentDialog; type DialogStoryMeta = Meta; const dismissed16Regular = html` -
openDialog(e, 'dialog-default')}>Open Dialog - x.modal} - ?alert=${x => x.alert} - ?no-focus-trap=${x => x.noFocusTrap} - hidden - > + Dialog - + + ${dismissed16Regular} + +

The Dialog component is a window overlaid on either the primary window or another dialog window. Windows under a modal dialog are inert. That is, users cannot interact with content outside an active dialog window.


- fluent-dialog + fluent-dialog + Close Dialog - Do Something + Do Something
`; @@ -65,47 +93,62 @@ const dialogTemplate = html` export default { title: 'Components/Dialog', args: { - modal: false, - alert: false, - noFocusTrap: false, + modalType: DialogModalType.modal, }, argTypes: { - modal: { - description: 'Renders dialog as a modal', + open: { + description: 'Controls the open state of the dialog', table: { - defaultValue: { - summary: false, - }, + defaultValue: { summary: false }, }, - control: 'boolean', }, - alert: { - description: 'Renders dialog as an alert', - table: { - defaultValue: { - summary: false, - }, - }, - control: 'boolean', + onOpenChange: { + description: + 'Event fired when the component transitions from its open state.

event: A CustomEvent emitted when the open state changes.

detail: An object containing relevant information, such as the open value and the type of interaction that triggered the event.', }, - noFocusTrap: { - description: 'removes trap focus', + modalType: { + description: + 'modal: When this type of dialog is open, the rest of the page is dimmed out and cannot be interacted with. The tab sequence is kept within the dialog and moving the focus outside the dialog will imply closing it. This is the default type of the component.

non-modal: When a non-modal dialog is open, the rest of the page is not dimmed out and users can interact with the rest of the page. This also implies that the tab focus can move outside the dialog when it reaches the last focusable element.

alert: A special type of modal dialog that interrupts the users workflow to communicate an important message or ask for a decision. Unlike a typical modal dialog, the user must take an action through the options given to dismiss the dialog, and it cannot be dismissed through the dimmed background.', table: { - defaultValue: { - summary: false, - }, + defaultValue: { summary: DialogModalType.modal }, + }, + control: { + type: 'select', + options: Object.values(DialogModalType), }, - control: 'boolean', + defaultValue: DialogModalType.modal, }, }, } as DialogStoryMeta; export const Default = renderComponent(dialogTemplate).bind({}); +export const NonModal = renderComponent(html` +
+ openDialog(e, 'dialog-nonmodal')}>Open Dialog + +
Non-modal
+ +

+ A non-modal Dialog by default presents no backdrop, allowing elements outside of the Dialog to be interacted with. + + A non-modal Dialog will present by default a closeButton. +

+ +

Note: if an element outside of the dialog is focused then it will not be possible to close the dialog with the Escape key.

+ modal-type="non-modal" + Close Dialog + Do Something +
+
+`); + export const Modal = renderComponent(html`
openDialog(e, 'dialog-modal')}>Open Dialog -
`); @@ -157,10 +160,13 @@ export const Modal = renderComponent(html`
modal-type="modal" - Close Dialog - Do Something + Do Something
`); @@ -176,10 +182,13 @@ export const Alert = renderComponent(html`
modal-type="alert" - Close Dialog - Do Something + Do Something
`); @@ -198,7 +207,7 @@ export const ControlledAndUncontrolledOpenAndClose = renderComponent(html - ${dismissed16Regular} + ${dismissed20Regular}
@@ -212,12 +221,12 @@ export const ControlledAndUncontrolledOpenAndClose = renderComponent(html Close Controlled Dialog - Do Something + Do Something
Uncontrolled Dialog
@@ -227,7 +236,7 @@ export const ControlledAndUncontrolledOpenAndClose = renderComponent(html - ${dismissed16Regular} + ${dismissed20Regular}
@@ -241,12 +250,12 @@ export const ControlledAndUncontrolledOpenAndClose = renderComponent(html Close Unontrolled Dialog - Do Something + Do Something
`); @@ -262,7 +271,7 @@ export const ScrollingLongContent = renderComponent(html` @click="${(e: Event, c) => closeDialog(e, 'dialog-longcontent')}" slot="title-action" > - ${dismissed16Regular} + ${dismissed20Regular}

@@ -316,57 +325,57 @@ export const ScrollingLongContent = renderComponent(html`

Close Dialog - Do Something + Do Something
`); -export const Actions = renderComponent(html` +export const FooterAction = renderComponent(html`
openDialog(e, 'dialog-fluidactions')}>Open Dialog -
Actions
+
Footer Action
- ${dismissed16Regular} + ${dismissed20Regular}
A Dialog should have no more than two - actions. + footer actions.
- However, if required, you can populate the actions slot with any number of buttons as needed.

- Something - Something Else + Something + Something Else Close Dialog - Something Else Entirely + Something Else Entirely
`); @@ -375,14 +384,14 @@ export const TitleCustomAction = renderComponent(html`
openDialog(e, 'dialog-titlecustomaction')}>Open Dialog -
No Header Actions
+
Title Custom Action
- ${rabbit16Regular} + ${dismissCircle20Regular}
@@ -403,12 +412,12 @@ export const TitleCustomAction = renderComponent(html`
Close Dialog - Do Something + Do Something
`); @@ -417,7 +426,7 @@ export const NoTitleAction = renderComponent(html`
openDialog(e, 'dialog-notitleaction')}>Open Dialog -
No Header Actions
+
No Title Action
`
Close Dialog - Do Something + Do Something
`); @@ -449,7 +458,7 @@ export const ChangeFocus = renderComponent(html` @click="${(e: Event, c) => closeDialog(e, 'dialog-changefocus')}" slot="title-action" > - ${dismissed16Regular} + ${dismissed20Regular} @@ -462,7 +471,7 @@ export const ChangeFocus = renderComponent(html`

change-focus="myElementId"

-
+
Close Dialog diff --git a/packages/web-components/src/dialog/dialog.styles.ts b/packages/web-components/src/dialog/dialog.styles.ts index 10c6dc2e444898..84d7fa43fd92a3 100644 --- a/packages/web-components/src/dialog/dialog.styles.ts +++ b/packages/web-components/src/dialog/dialog.styles.ts @@ -27,25 +27,6 @@ import { display } from '@microsoft/fast-foundation'; export const styles = css` ${display('flex')} - :host([hidden]) { - display: none; - } - - .overlay { - position: fixed; - inset: 0; - background: ${colorBackgroundOverlay}; - touch-action: none; - } - - .positioning-region { - display: flex; - justify-content: center; - position: fixed; - inset: 0; - z-index: var(--dialog-elevation, 9999); - } - dialog { background: ${colorNeutralBackground1}; border: ${strokeWidthThin} solid ${colorTransparentStroke}; @@ -63,8 +44,8 @@ export const styles = css` padding: 0; } - :host([modal-type='non-modal'][inert-trap-focus]) dialog::backdrop { - display: none; + dialog::backdrop { + background: rgba(0, 0, 0, 0.4); } .root { @@ -101,14 +82,6 @@ export const styles = css` box-sizing: border-box; } - dialog { - max-width: 100%; - width: 100vh; - } - /* .root { - max-width: 100vw; - grid-template-rows: auto 1fr auto; - } */ .footer { display: flex; grid-column-start: 1; @@ -119,12 +92,12 @@ export const styles = css` justify-self: stretch; width: 100%; } - ::slotted([slot='actions']) { + ::slotted([slot='footer-action']) { width: 100%; } @media screen and (min-width: 480px) { - ::slotted([slot='actions']) { + ::slotted([slot='footer-action']) { width: fit-content; } dialog { diff --git a/packages/web-components/src/dialog/dialog.template.ts b/packages/web-components/src/dialog/dialog.template.ts index fc372c5b04443e..1c30e9a6291a40 100644 --- a/packages/web-components/src/dialog/dialog.template.ts +++ b/packages/web-components/src/dialog/dialog.template.ts @@ -22,48 +22,47 @@ const dismissed16Regular = html.partial(` * @public */ export const template: ElementViewTemplate = html` - -
- -
- - - ${when( - x => x.modalType === DialogModalType.nonModal && x.titleAction.length === 0 && !x.noTitleAction, - html` x.dismiss()} - ${ref('defaultTitleAction')} - >${dismissed16Regular}`, - )} -
-
- -
- - -
+ +
+ +
+ + + ${when( + x => x.modalType === DialogModalType.nonModal && x.titleAction.length === 0 && !x.noTitleAction, + html` x.dismiss()} + ${ref('defaultTitleAction')} + >${dismissed16Regular}`, + )} +
+
+ +
+ +
+
`; From bf6bf37312b201a2a75a377cb5bb7ee5d869e55c Mon Sep 17 00:00:00 2001 From: brianchristopherbrady Date: Mon, 23 Oct 2023 11:36:11 -0700 Subject: [PATCH 31/45] dialog: updates README --- packages/web-components/src/dialog/README.md | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/packages/web-components/src/dialog/README.md b/packages/web-components/src/dialog/README.md index f213a9f243d75f..a6570d772119f8 100644 --- a/packages/web-components/src/dialog/README.md +++ b/packages/web-components/src/dialog/README.md @@ -23,7 +23,7 @@ Fluent WC3 Dialog has feature parity with the Fluent UI React 9 Dialog implement ### **Basic Implemenation** ```html - + Dialog @@ -40,12 +40,12 @@ Fluent WC3 Dialog has feature parity with the Fluent UI React 9 Dialog implement | Name | Privacy | Type | Default | Description | | ------------------ | ------- | ----------------- | ----------------------- | --------------------------------------------------------- | | `modal-type` | public | `DialogModalType` | `DialogModalType.modal` | Indicates that the type of modal to render. | -| `change-focus` | public | `string` | `undefined` | Used to set id of desired focus target. | | `open` | public | `boolean` | `false` | Controls the open state of the dialog | | `no-title-action` | public | `boolean` | `false` | Used to set whether the default title action is rendered. | -| `aria-labelledby` | public | `boolean` | `false` | optional based on implementation\*\* | -| `aria-describedby` | public | `boolean` | `false` | optional based on implementation\*\* | -| `aria-label ` | public | `boolean` | `false` | optional based on implementation\*\* | +| `change-focus` | public | `string` | `undefined` | Used to set id of desired focus target. | +| `aria-labelledby` | public | `string` | `undefined` | optional based on implementation\*\* | +| `aria-describedby` | public | `string` | `undefined` | optional based on implementation\*\* | +| `aria-label ` | public | `string` | `undefined` | optional based on implementation\*\* | \*\* See the [W3C Specification](https://w3c.github.io/aria-practices/#dialog_roles_states_props) for requirements and details. @@ -73,9 +73,9 @@ Fluent WC3 Dialog has feature parity with the Fluent UI React 9 Dialog implement ### **Events** -| Name | Description | -| -------------- | --------------------------------------------------------------- | -| `onOpenChange` | Event fired when the component transitions from its open state. | +| Name | Description | Details | +| -------------- | --------------------------------------------------------------- | -------------------------------------------------- | +| `onOpenChange` | Event fired when the component transitions from its open state. | `{ open: this.dialog.open, dismissed: dismissed }` | ## **Preparation** From 0e78c127f6791bb3590188030925c4218ac64023 Mon Sep 17 00:00:00 2001 From: brianchristopherbrady Date: Mon, 23 Oct 2023 14:24:35 -0700 Subject: [PATCH 32/45] dialog: updates template class names --- packages/web-components/src/dialog/dialog.template.ts | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/packages/web-components/src/dialog/dialog.template.ts b/packages/web-components/src/dialog/dialog.template.ts index 1c30e9a6291a40..ed9a64e920cede 100644 --- a/packages/web-components/src/dialog/dialog.template.ts +++ b/packages/web-components/src/dialog/dialog.template.ts @@ -47,7 +47,8 @@ export const template: ElementViewTemplate = html` x => x.modalType === DialogModalType.nonModal && x.titleAction.length === 0 && !x.noTitleAction, html` x.dismiss()} From 71b0a2346336ee66380ffe6d15294e8b8985898a Mon Sep 17 00:00:00 2001 From: brianchristopherbrady Date: Mon, 23 Oct 2023 14:27:46 -0700 Subject: [PATCH 33/45] dialog: updates backdrop to use fluent token --- packages/web-components/src/dialog/dialog.styles.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/web-components/src/dialog/dialog.styles.ts b/packages/web-components/src/dialog/dialog.styles.ts index 84d7fa43fd92a3..2c3d5e23bcbbb2 100644 --- a/packages/web-components/src/dialog/dialog.styles.ts +++ b/packages/web-components/src/dialog/dialog.styles.ts @@ -45,7 +45,7 @@ export const styles = css` } dialog::backdrop { - background: rgba(0, 0, 0, 0.4); + background: ${colorBackgroundOverlay}; } .root { From 4ae3e6287934ddc62f2afe1439661a077b5d5567 Mon Sep 17 00:00:00 2001 From: brianchristopherbrady Date: Mon, 23 Oct 2023 14:58:49 -0700 Subject: [PATCH 34/45] dialog: adds two column layout story --- .../src/dialog/dialog.stories.ts | 42 ++++++++++++++++++- 1 file changed, 40 insertions(+), 2 deletions(-) diff --git a/packages/web-components/src/dialog/dialog.stories.ts b/packages/web-components/src/dialog/dialog.stories.ts index bffbf3e5f57ed5..8327a037b8f083 100644 --- a/packages/web-components/src/dialog/dialog.stories.ts +++ b/packages/web-components/src/dialog/dialog.stories.ts @@ -40,9 +40,9 @@ const dismissCircle20Regular = html` `; -const closeDialog = (e: Event, id: string) => { +const closeDialog = (e: Event, id: string, dismissed: boolean = false) => { const dialog = document.getElementById(id) as FluentDialog; - dialog.hide(); + dialog.hide(dismissed); }; const openDialog = (e: Event, id: string) => { @@ -260,6 +260,44 @@ export const ControlledAndUncontrolledOpenAndClose = renderComponent(html `); +export const TwoColumnLayout = renderComponent(html` +
+ openDialog(e, 'dialog-twocolumn')}>Open Dialog + +
Sign Up
+
+
+

The dialog is designed with flexibility in mind, accommodating multiple column layouts within its structure.

+
+
+ + First Name + +
+ + Last Name + +
+ + Email + +
+ + Phone Number + +
+
+ + Submit + Cancel +
+
+`); + export const ScrollingLongContent = renderComponent(html`
openDialog(e, 'dialog-longcontent')}>Open Dialog From 6f01f6c408e83f8170a06b94efea604d58494b7a Mon Sep 17 00:00:00 2001 From: brianchristopherbrady Date: Mon, 23 Oct 2023 16:29:31 -0700 Subject: [PATCH 35/45] dialog: adds additional stories --- .../src/dialog/dialog.stories.ts | 211 +++++++++++++++--- 1 file changed, 175 insertions(+), 36 deletions(-) diff --git a/packages/web-components/src/dialog/dialog.stories.ts b/packages/web-components/src/dialog/dialog.stories.ts index 8327a037b8f083..8360ba82f86877 100644 --- a/packages/web-components/src/dialog/dialog.stories.ts +++ b/packages/web-components/src/dialog/dialog.stories.ts @@ -74,7 +74,7 @@ const dialogTemplate = html` Dialog

- The Dialog component is a window overlaid on either the primary window or another dialog window. Windows under + The dialog component is a window overlaid on either the primary window or another dialog window. Windows under a modal dialog are inert. That is, users cannot interact with content outside an active dialog window.

@@ -127,15 +127,25 @@ export const Default = renderComponent(dialogTemplate).bind({}); export const NonModal = renderComponent(html`
+ + + A non-modal dialog by default presents no backdrop, allowing elements outside of the dialog to be interacted with. + A non-modal dialog will present by default a close button. + + +
+

Note: if an element outside of the dialog is focused then it will not be possible to close the dialog with the Escape key.

+
+ openDialog(e, 'dialog-nonmodal')}>Open Dialog
Non-modal
-

- A non-modal Dialog by default presents no backdrop, allowing elements outside of the Dialog to be interacted with. +

+ A non-modal dialog by default presents no backdrop, allowing elements outside of the dialog to be interacted with. - A non-modal Dialog will present by default a closeButton. -

+ A non-modal dialog will present by default a closeButton. +

Note: if an element outside of the dialog is focused then it will not be possible to close the dialog with the Escape key.

modal-type="non-modal" @@ -150,6 +160,14 @@ export const NonModal = renderComponent(html` export const Modal = renderComponent(html`
+ + + A modal is a type of dialog that temporarily halts the main workflow to convey a significant message or require + user interaction. By default, interactions such as clicking outside the dialog or pressing the Escape key will + close the modal-dialog, resuming the user's interaction with the main content. + + +
openDialog(e, 'dialog-modal')}>Open Dialog
Modal
@@ -173,6 +191,13 @@ export const Modal = renderComponent(html` export const Alert = renderComponent(html`
+ + + An alert is a type of modal-dialog that interrupts the user's workflow to communicate an important message and + acquire a response. By default clicking on backdrop and pressing Escape will not dismiss an alert Dialog. + + +
openDialog(e, 'dialog-alert')}>Open Dialog
Alert
@@ -193,12 +218,31 @@ export const Alert = renderComponent(html`
`); -export const ControlledAndUncontrolledOpenAndClose = renderComponent(html` +export const ControlledAndUncontrolled = renderComponent(html`
- openDialogControlled(e, 'dialog-controlled')} - >Open Controlled Dialog + + + Employ the open attribute to dictate the dialog's visibility state. This method offers a declarative approach, + where the dialog's visibility is determined by the presence or absence of the external open attribute, ensuring + the state is managed outside the component. + + +
+ openDialogControlled(e, 'dialog-controlled')}> + Open Controlled Dialog + +
+
+ + + Utilize the show and hide methods to manage the dialog's visibility. This approach + allows the dialog to handle its state internally, giving you a direct and programmatic way to toggle its display + without relying on external attributes. + + +
openDialog(e, 'dialog-uncontrolled')}>Open Uncontrolled Dialog +
Controlled Dialog
Close Controlled Dialog + Close Controlled Dialog + Do Something
@@ -241,9 +286,9 @@ export const ControlledAndUncontrolledOpenAndClose = renderComponent(html - Utilize the show and hide methods to manage the dialog's visibility. This approach allows the dialog to - handle its state internally, giving you a direct and programmatic way to toggle its display without relying - on external attributes. + Utilize the show and hide methods to manage the dialog's visibility. This approach + allows the dialog to handle its state internally, giving you a direct and programmatic way to toggle its + display without relying on external attributes.
@@ -253,8 +298,9 @@ export const ControlledAndUncontrolledOpenAndClose = renderComponent(htmlClose Unontrolled Dialog + Close Uncontrolled Dialog + Do Something
@@ -262,44 +308,96 @@ export const ControlledAndUncontrolledOpenAndClose = renderComponent(html`
+

+ The dialog is designed with flexibility in mind, accommodating multiple column layouts within its structure. +

+
openDialog(e, 'dialog-twocolumn')}>Open Dialog -
Sign Up
-
-
-

The dialog is designed with flexibility in mind, accommodating multiple column layouts within its structure.

+
Welcome!
+
+

+ The dialog is designed with flexibility in mind, accommodating multiple column layouts within its structure. +

+
+
+
+ + image layout story +
- - First Name - +

Don't have an account? Sign up now!


- - Last Name + + Email
- Email + Username
- - Phone Number + + Password +
- Submit - Cancel + Sign Up + +
+`); + +export const RTL = renderComponent(html` +
+

+ The dialog component seamlessly supports both Right-to-Left (RTL) and Left-to-Right (LTR) text directions, + ensuring flexibility for various language orientations. +

+
+ openDialog(e, 'dialog-rtl')}>Open Dialog + + +
أهلاً!
+ + ${dismissed20Regular} + +

هذا المكون يدعم كلاً من LTR و RTL.

+ + إلغاء + قم بشيء
`); export const ScrollingLongContent = renderComponent(html`
+

+ By default content provided in the default slot should grow until it fits viewport size, overflowed content will + be scrollable +

+
openDialog(e, 'dialog-longcontent')}>Open Dialog
Scrolling Long Content
@@ -375,6 +473,19 @@ export const ScrollingLongContent = renderComponent(html` export const FooterAction = renderComponent(html`
+

+ A dialog should have no more than + two + footer actions. +

+ + However, if required, you can populate the footer-action slot with any number of buttons as needed. +
openDialog(e, 'dialog-fluidactions')}>Open Dialog
Footer Action
@@ -389,7 +500,7 @@ export const FooterAction = renderComponent(html`
A Dialog should have no more than + >A dialog should have no more than two footer actions. ` export const TitleCustomAction = renderComponent(html`
+ + By default if the dialog is set to modal-type='non-modal' a button with a close icon is provided + to close the dialog as action slot. + + +
+ + + This slot can be customized to add a different kind of action, that it'll be available in any kind of dialog, + ignoring the modalType property, here's an example replacing the simple close icon with a fluent + button using a different icon. + + +
openDialog(e, 'dialog-titlecustomaction')}>Open Dialog
Title Custom Action
@@ -434,16 +560,16 @@ export const TitleCustomAction = renderComponent(html`
By default if Dialog has modalType='non-modal' a button with a close icon is provided to close the dialog - as action slot. + >By default if the dialog is set to modal-type='non-modal' a button with a close icon is + provided to close the dialog as action slot.
This slot can be customized to add a different kind of action, that it'll be available in any kind of - Dialog, ignoring the modalType property, here's an example replacing the simple close icon with a fluent - button using a different icon. + dialog, ignoring the modalType property, here's an example replacing the simple close icon with + a fluent button using a different icon.
@@ -462,6 +588,12 @@ export const TitleCustomAction = renderComponent(html` export const NoTitleAction = renderComponent(html`
+

+ The no-title-action attribute can be provided to opt out of rendering any title action. +

+
openDialog(e, 'dialog-notitleaction')}>Open Dialog
No Title Action
@@ -487,6 +619,13 @@ export const NoTitleAction = renderComponent(html` export const ChangeFocus = renderComponent(html`
+

+ Changing the default focused element can be done by providing the id of the element to focus on in the + change-focus attribute. +

+
openDialog(e, 'dialog-changefocus')}>Open Dialog
Change Focus
@@ -502,7 +641,7 @@ export const ChangeFocus = renderComponent(html`

Changing the default focused element can be done by providing the id of the element to focus on in the - change-focus attribute. + change-focus attribute.


From 573d51101cd8a244c17845334787a8a64c51d761 Mon Sep 17 00:00:00 2001 From: brianchristopherbrady Date: Mon, 23 Oct 2023 16:39:42 -0700 Subject: [PATCH 36/45] dialog: adds exports to index and package json --- packages/web-components/package.json | 5 +++++ packages/web-components/src/index.ts | 1 + 2 files changed, 6 insertions(+) diff --git a/packages/web-components/package.json b/packages/web-components/package.json index 6017b0f8ca42e5..eeb11797b3dc9c 100644 --- a/packages/web-components/package.json +++ b/packages/web-components/package.json @@ -59,6 +59,10 @@ "types": "./dist/dts/counter-badge/define.d.ts", "default": "./dist/esm/counter-badge/define.js" }, + "./dialog.js": { + "types": "./dist/dts/dialog/define.d.ts", + "default": "./dist/esm/dialog/define.js" + }, "./divider.js": { "types": "./dist/dts/divider/define.d.ts", "default": "./dist/esm/divider/define.js" @@ -150,6 +154,7 @@ "./dist/esm/checkbox/define.js", "./dist/esm/compound-button/define.js", "./dist/esm/counter-badge/define.js", + "./dist/esm/dialog/define.js", "./dist/esm/divider/define.js", "./dist/esm/image/define.js", "./dist/esm/label/define.js", diff --git a/packages/web-components/src/index.ts b/packages/web-components/src/index.ts index 92750616f07850..a5d24a242b792c 100644 --- a/packages/web-components/src/index.ts +++ b/packages/web-components/src/index.ts @@ -7,6 +7,7 @@ export * from './button/index.js'; export * from './checkbox/index.js'; export * from './compound-button/index.js'; export * from './counter-badge/index.js'; +export * from './dialog/index.js'; export * from './divider/index.js'; export * from './image/index.js'; export * from './label/index.js'; From 93a32630c01f7e73d4f1228d6fc7ab39922dee4a Mon Sep 17 00:00:00 2001 From: brianchristopherbrady Date: Mon, 23 Oct 2023 18:19:49 -0700 Subject: [PATCH 37/45] dialog: fixes style token imports --- .../src/dialog/dialog.stories.ts | 59 +++++++++++++------ .../src/dialog/dialog.styles.ts | 12 ++-- 2 files changed, 50 insertions(+), 21 deletions(-) diff --git a/packages/web-components/src/dialog/dialog.stories.ts b/packages/web-components/src/dialog/dialog.stories.ts index 8360ba82f86877..e75d7b2c7ff5de 100644 --- a/packages/web-components/src/dialog/dialog.stories.ts +++ b/packages/web-components/src/dialog/dialog.stories.ts @@ -52,14 +52,12 @@ const openDialog = (e: Event, id: string) => { const openDialogControlled = (e: Event, id: string) => { const dialog = document.getElementById(id) as FluentDialog; - dialog.open = true; - dialog.show(); + dialog.setAttribute('open', ''); }; const closeDialogControlled = (e: Event, id: string) => { const dialog = document.getElementById(id) as FluentDialog; - dialog.open = false; - dialog.hide(); + dialog.removeAttribute('open'); }; const dialogTemplate = html` @@ -70,7 +68,12 @@ const dialogTemplate = html`
openDialog(e, 'dialog-default')}>Open Dialog - + Dialog

@@ -80,14 +83,14 @@ const dialogTemplate = html`
fluent-dialog - Close Dialog - Do Something + Do Something

`; @@ -98,16 +101,6 @@ export default { modalType: DialogModalType.modal, }, argTypes: { - open: { - description: 'Controls the open state of the dialog', - table: { - defaultValue: { summary: false }, - }, - }, - onOpenChange: { - description: - 'Event fired when the component transitions from its open state.

event: A CustomEvent emitted when the open state changes.

detail: An object containing relevant information, such as the open value and the type of interaction that triggered the event.', - }, modalType: { description: 'modal: When this type of dialog is open, the rest of the page is dimmed out and cannot be interacted with. The tab sequence is kept within the dialog and moving the focus outside the dialog will imply closing it. This is the default type of the component.

non-modal: When a non-modal dialog is open, the rest of the page is not dimmed out and users can interact with the rest of the page. This also implies that the tab focus can move outside the dialog when it reaches the last focusable element.

alert: A special type of modal dialog that interrupts the users workflow to communicate an important message or ask for a decision. Unlike a typical modal dialog, the user must take an action through the options given to dismiss the dialog, and it cannot be dismissed through the dimmed background.', @@ -120,6 +113,38 @@ export default { }, defaultValue: DialogModalType.modal, }, + changeFocus: { + description: 'Used to set the id of the element that should receive focus when the dialog is opened', + table: { + defaultValue: { summary: 'undefined' }, + }, + control: { + type: 'select', + options: ['dialog-default-close', 'dialog-default-dosomething'], + }, + defaultValue: undefined, + }, + noTitleAction: { + description: + 'Used to opt out of rendering the default title action that is rendered when the dialog typeis set to non-modal', + table: { + defaultValue: { summary: false }, + }, + control: { + type: 'boolean', + }, + defaultValue: false, + }, + open: { + description: 'Controls the open state of the dialog', + table: { + defaultValue: { summary: false }, + }, + }, + onOpenChange: { + description: + 'Event fired when the component transitions from its open state.

event: A CustomEvent emitted when the open state changes.

detail: An object containing relevant information, such as the open value and the type of interaction that triggered the event.', + }, }, } as DialogStoryMeta; diff --git a/packages/web-components/src/dialog/dialog.styles.ts b/packages/web-components/src/dialog/dialog.styles.ts index 2c3d5e23bcbbb2..c0fefcdfd84d7f 100644 --- a/packages/web-components/src/dialog/dialog.styles.ts +++ b/packages/web-components/src/dialog/dialog.styles.ts @@ -1,3 +1,5 @@ +import { css } from '@microsoft/fast-element'; +import { display } from '@microsoft/fast-foundation'; import { borderRadiusXLarge, colorBackgroundOverlay, @@ -17,9 +19,7 @@ import { spacingVerticalS, spacingVerticalXXL, strokeWidthThin, -} from '@fluentui/web-components'; -import { css } from '@microsoft/fast-element'; -import { display } from '@microsoft/fast-foundation'; +} from '../theme/design-tokens.js'; /** Dialog styles * @public @@ -27,6 +27,10 @@ import { display } from '@microsoft/fast-foundation'; export const styles = css` ${display('flex')} + :host { + --dialog-backdrop: ${colorBackgroundOverlay}; + } + dialog { background: ${colorNeutralBackground1}; border: ${strokeWidthThin} solid ${colorTransparentStroke}; @@ -45,7 +49,7 @@ export const styles = css` } dialog::backdrop { - background: ${colorBackgroundOverlay}; + background: var(--dialog-backdrop, rgba(0, 0, 0, 0.4)); } .root { From 6b1d7e49a00cbb756b3aae9fe37a494fef24a713 Mon Sep 17 00:00:00 2001 From: brianchristopherbrady Date: Tue, 24 Oct 2023 02:40:14 -0700 Subject: [PATCH 38/45] dialog: cleans up open state --- packages/web-components/src/dialog/README.md | 2 - .../src/dialog/dialog.stories.ts | 60 +------------------ .../src/dialog/dialog.template.ts | 6 +- packages/web-components/src/dialog/dialog.ts | 23 ++----- 4 files changed, 7 insertions(+), 84 deletions(-) diff --git a/packages/web-components/src/dialog/README.md b/packages/web-components/src/dialog/README.md index a6570d772119f8..7d80528d44c4d5 100644 --- a/packages/web-components/src/dialog/README.md +++ b/packages/web-components/src/dialog/README.md @@ -68,8 +68,6 @@ Fluent WC3 Dialog has feature parity with the Fluent UI React 9 Dialog implement | `title-action` | slot for close button | | | default slot for content rendered between title and footer | | `footer-action` | slot for actions content | -| `start` | slot for content at the start of the dialog | -| `end` | slot for content at the end of the dialog | ### **Events** diff --git a/packages/web-components/src/dialog/dialog.stories.ts b/packages/web-components/src/dialog/dialog.stories.ts index e75d7b2c7ff5de..e497b63ec518ae 100644 --- a/packages/web-components/src/dialog/dialog.stories.ts +++ b/packages/web-components/src/dialog/dialog.stories.ts @@ -68,12 +68,7 @@ const dialogTemplate = html`
openDialog(e, 'dialog-default')}>Open Dialog - + Dialog

@@ -113,17 +108,6 @@ export default { }, defaultValue: DialogModalType.modal, }, - changeFocus: { - description: 'Used to set the id of the element that should receive focus when the dialog is opened', - table: { - defaultValue: { summary: 'undefined' }, - }, - control: { - type: 'select', - options: ['dialog-default-close', 'dialog-default-dosomething'], - }, - defaultValue: undefined, - }, noTitleAction: { description: 'Used to opt out of rendering the default title action that is rendered when the dialog typeis set to non-modal', @@ -641,45 +625,3 @@ export const NoTitleAction = renderComponent(html`

`); - -export const ChangeFocus = renderComponent(html` -
-

- Changing the default focused element can be done by providing the id of the element to focus on in the - change-focus attribute. -

-
- openDialog(e, 'dialog-changefocus')}>Open Dialog - -
Change Focus
- - ${dismissed20Regular} - - - -

- Changing the default focused element can be done by providing the id of the element to focus on in the - change-focus attribute. -

-
-
- -

change-focus="myElementId"

-
-
- Close Dialog - - Focus Me First -
-
-
-`); diff --git a/packages/web-components/src/dialog/dialog.template.ts b/packages/web-components/src/dialog/dialog.template.ts index ed9a64e920cede..dc5590b6f62285 100644 --- a/packages/web-components/src/dialog/dialog.template.ts +++ b/packages/web-components/src/dialog/dialog.template.ts @@ -27,8 +27,8 @@ export const template: ElementViewTemplate = html` role="${x => (x.modalType === DialogModalType.alert ? 'alertdialog' : 'dialog')}" modal-type="${x => x.modalType}" change-focus="${x => x.changeFocus}" - class="control" - part="control" + class="dialog" + part="dialog" aria-modal="${x => x.modalType === DialogModalType.modal || x.modalType === DialogModalType.alert ? 'true' : void 0}" aria-describedby="${x => x.ariaDescribedby}" @@ -39,7 +39,6 @@ export const template: ElementViewTemplate = html` ${ref('dialog')} >
-
@@ -63,7 +62,6 @@ export const template: ElementViewTemplate = html` -
`; diff --git a/packages/web-components/src/dialog/dialog.ts b/packages/web-components/src/dialog/dialog.ts index fafdb223f01c6a..a112c566e2dc27 100644 --- a/packages/web-components/src/dialog/dialog.ts +++ b/packages/web-components/src/dialog/dialog.ts @@ -146,11 +146,6 @@ export class Dialog extends FASTElement { } else { this.inertTrapFocus = false; } - if (this.open) { - this.show(); - } else { - this.open = this.dialog.open; - } } /** @@ -170,20 +165,11 @@ export class Dialog extends FASTElement { Updates.enqueue(() => { if (this.modalType === DialogModalType.alert || this.modalType === DialogModalType.modal) { this.dialog.showModal(); - this.open = true; this.updateTrapFocus(true); } else if (this.modalType === DialogModalType.nonModal) { this.dialog.show(); - this.open = true; } this.onOpenChangeEvent(); - if (this.changeFocus) { - const element = this.querySelector(`#${this.changeFocus}`) as HTMLElement; - if (element) { - element.focus(); - return; - } - } }); } @@ -194,7 +180,6 @@ export class Dialog extends FASTElement { */ public hide(dismissed: boolean = false): void { this.dialog.close(); - this.open = false; this.onOpenChangeEvent(dismissed); } @@ -217,7 +202,7 @@ export class Dialog extends FASTElement { */ public handleClick(event: Event): boolean { event.preventDefault(); - if (this.open && this.modalType !== DialogModalType.alert && event.target === this.dialog) { + if (this.dialog.open && this.modalType !== DialogModalType.alert && event.target === this.dialog) { this.dismiss(); } return true; @@ -251,7 +236,7 @@ export class Dialog extends FASTElement { * @param e - The keydown event */ private handleDocumentKeydown = (e: KeyboardEvent): void => { - if (!e.defaultPrevented && this.open) { + if (!e.defaultPrevented && this.dialog.open) { switch (e.key) { case keyTab: this.handleTabKeyDown(e); @@ -266,7 +251,7 @@ export class Dialog extends FASTElement { * @param e - The keydown event */ private handleTabKeyDown = (e: KeyboardEvent): void => { - if (!this.inertTrapFocus || !this.open) { + if (!this.inertTrapFocus || !this.dialog.open) { return; } @@ -332,7 +317,7 @@ export class Dialog extends FASTElement { * @returns boolean */ private shouldTrapFocus = (): boolean => { - return this.inertTrapFocus && this.open; + return this.inertTrapFocus && this.dialog.open; }; /** From e8823ba71f26d4c1f185f35f7f3434fee2375da5 Mon Sep 17 00:00:00 2001 From: brianchristopherbrady Date: Tue, 24 Oct 2023 10:31:12 -0700 Subject: [PATCH 39/45] dialog: updates template slot names --- .../src/dialog/dialog.stories.ts | 65 ++++++++----------- .../src/dialog/dialog.styles.ts | 10 +-- .../src/dialog/dialog.template.ts | 6 +- 3 files changed, 36 insertions(+), 45 deletions(-) diff --git a/packages/web-components/src/dialog/dialog.stories.ts b/packages/web-components/src/dialog/dialog.stories.ts index e497b63ec518ae..4b20bc034dbe89 100644 --- a/packages/web-components/src/dialog/dialog.stories.ts +++ b/packages/web-components/src/dialog/dialog.stories.ts @@ -80,12 +80,12 @@ const dialogTemplate = html` fluent-dialog Close Dialog - Do Something + Do Something
`; @@ -158,11 +158,10 @@ export const NonModal = renderComponent(html`

Note: if an element outside of the dialog is focused then it will not be possible to close the dialog with the Escape key.

modal-type="non-modal" - Close Dialog - Do Something + Do Something
`); @@ -187,13 +186,10 @@ export const Modal = renderComponent(html`

modal-type="modal" - Close Dialog - Do Something + Do Something
`); @@ -216,13 +212,10 @@ export const Alert = renderComponent(html`

modal-type="alert" - Close Dialog - Do Something + Do Something
`); @@ -274,13 +267,13 @@ export const ControlledAndUncontrolled = renderComponent(html`
Close Controlled Dialog - Do Something + Do Something
Uncontrolled Dialog
@@ -304,13 +297,13 @@ export const ControlledAndUncontrolled = renderComponent(html`
Close Uncontrolled Dialog - Do Something + Do Something
`); @@ -359,10 +352,10 @@ export const TwoColumnLayout = renderComponent(html`
- Cancel - Sign Up + Sign Up
`); @@ -390,10 +383,8 @@ export const RTL = renderComponent(html`

هذا المكون يدعم كلاً من LTR و RTL.

- إلغاء - قم بشيء + إلغاء + قم بشيء
`); @@ -470,12 +461,12 @@ export const ScrollingLongContent = renderComponent(html`

Close Dialog - Do Something + Do Something
`); @@ -491,7 +482,7 @@ export const FooterAction = renderComponent(html` > - However, if required, you can populate the footer-action slot with any number of buttons as needed.
@@ -517,23 +508,23 @@ export const FooterAction = renderComponent(html`
- However, if required, you can populate the footer-action slot with any number of buttons as needed.

- Something - Something Else + Something + Something Else Close Dialog - Something Else Entirely + Something Else Entirely
`); @@ -585,12 +576,12 @@ export const TitleCustomAction = renderComponent(html`
Close Dialog - Do Something + Do Something `); @@ -616,12 +607,12 @@ export const NoTitleAction = renderComponent(html`
Close Dialog - Do Something + Do Something `); diff --git a/packages/web-components/src/dialog/dialog.styles.ts b/packages/web-components/src/dialog/dialog.styles.ts index c0fefcdfd84d7f..5185d9468f0222 100644 --- a/packages/web-components/src/dialog/dialog.styles.ts +++ b/packages/web-components/src/dialog/dialog.styles.ts @@ -61,7 +61,7 @@ export const styles = css` padding: ${spacingVerticalXXL} ${spacingHorizontalXXL}; } - .header { + .title { font-size: ${fontSizeBase500}; line-height: ${lineHeightBase500}; font-weight: ${fontWeightSemibold}; @@ -86,7 +86,7 @@ export const styles = css` box-sizing: border-box; } - .footer { + .actions { display: flex; grid-column-start: 1; flex-direction: column; @@ -96,19 +96,19 @@ export const styles = css` justify-self: stretch; width: 100%; } - ::slotted([slot='footer-action']) { + ::slotted([slot='action']) { width: 100%; } @media screen and (min-width: 480px) { - ::slotted([slot='footer-action']) { + ::slotted([slot='action']) { width: fit-content; } dialog { max-width: 600px; width: 100%; } - .footer { + .actions { display: flex; flex-direction: row; justify-content: flex-end; diff --git a/packages/web-components/src/dialog/dialog.template.ts b/packages/web-components/src/dialog/dialog.template.ts index dc5590b6f62285..5edad2f3d7b3af 100644 --- a/packages/web-components/src/dialog/dialog.template.ts +++ b/packages/web-components/src/dialog/dialog.template.ts @@ -39,7 +39,7 @@ export const template: ElementViewTemplate = html` ${ref('dialog')} >
-
+
${when( @@ -59,8 +59,8 @@ export const template: ElementViewTemplate = html`
-
From 614cfdd1481d296ad9a0a5d82be87fa293597b33 Mon Sep 17 00:00:00 2001 From: brianchristopherbrady Date: Tue, 24 Oct 2023 10:40:30 -0700 Subject: [PATCH 40/45] dialog: updates property name --- packages/web-components/src/dialog/dialog.ts | 21 ++++++++++---------- 1 file changed, 11 insertions(+), 10 deletions(-) diff --git a/packages/web-components/src/dialog/dialog.ts b/packages/web-components/src/dialog/dialog.ts index a112c566e2dc27..d0f8c499bda5f5 100644 --- a/packages/web-components/src/dialog/dialog.ts +++ b/packages/web-components/src/dialog/dialog.ts @@ -107,7 +107,7 @@ export class Dialog extends FASTElement { * @private * Indicates whether focus should be trapped within the dialog */ - private inertTrapFocus: boolean = false; + private trapFocus: boolean = false; /** * @public @@ -128,11 +128,12 @@ export class Dialog extends FASTElement { * Method called when the 'modalType' attribute changes */ public modalTypeChanged(oldValue: DialogModalType, newValue: DialogModalType): void { - if ( - newValue !== oldValue && - (this.modalType === DialogModalType.modal || this.modalType !== DialogModalType.alert) - ) { - this.inertTrapFocus = true; + if (newValue !== oldValue) { + if (newValue == DialogModalType.alert || newValue == DialogModalType.modal) { + this.trapFocus = true; + } else { + this.trapFocus = false; + } } } @@ -142,9 +143,9 @@ export class Dialog extends FASTElement { */ public setComponent(): void { if (this.modalType == DialogModalType.modal || this.modalType == DialogModalType.alert) { - this.inertTrapFocus = true; + this.trapFocus = true; } else { - this.inertTrapFocus = false; + this.trapFocus = false; } } @@ -251,7 +252,7 @@ export class Dialog extends FASTElement { * @param e - The keydown event */ private handleTabKeyDown = (e: KeyboardEvent): void => { - if (!this.inertTrapFocus || !this.dialog.open) { + if (!this.trapFocus || !this.dialog.open) { return; } @@ -317,7 +318,7 @@ export class Dialog extends FASTElement { * @returns boolean */ private shouldTrapFocus = (): boolean => { - return this.inertTrapFocus && this.dialog.open; + return this.trapFocus && this.dialog.open; }; /** From 7ded0329eca17626583103cc51d9f379a7d3c251 Mon Sep 17 00:00:00 2001 From: brianchristopherbrady Date: Tue, 24 Oct 2023 11:00:02 -0700 Subject: [PATCH 41/45] dialog: removes change-focus --- packages/web-components/src/dialog/dialog.template.ts | 1 - packages/web-components/src/dialog/dialog.ts | 7 ------- 2 files changed, 8 deletions(-) diff --git a/packages/web-components/src/dialog/dialog.template.ts b/packages/web-components/src/dialog/dialog.template.ts index 5edad2f3d7b3af..7fe67e712070c1 100644 --- a/packages/web-components/src/dialog/dialog.template.ts +++ b/packages/web-components/src/dialog/dialog.template.ts @@ -26,7 +26,6 @@ export const template: ElementViewTemplate = html` ?open="${x => x.open}" role="${x => (x.modalType === DialogModalType.alert ? 'alertdialog' : 'dialog')}" modal-type="${x => x.modalType}" - change-focus="${x => x.changeFocus}" class="dialog" part="dialog" aria-modal="${x => diff --git a/packages/web-components/src/dialog/dialog.ts b/packages/web-components/src/dialog/dialog.ts index d0f8c499bda5f5..d87d9b2fe9f5f3 100644 --- a/packages/web-components/src/dialog/dialog.ts +++ b/packages/web-components/src/dialog/dialog.ts @@ -75,13 +75,6 @@ export class Dialog extends FASTElement { @attr({ attribute: 'aria-labelledby' }) public ariaLabelledby?: string; - /** - * @public - * The ID of the element to focus when the dialog opens - */ - @attr({ attribute: 'change-focus' }) - public changeFocus?: string; - /** * @public * The type of the dialog modal From 975da6e7333d8c61e495fd331cdcb0c97377d5ac Mon Sep 17 00:00:00 2001 From: brianchristopherbrady Date: Tue, 24 Oct 2023 11:04:19 -0700 Subject: [PATCH 42/45] dialog: syncs open attr --- packages/web-components/src/dialog/dialog.ts | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/packages/web-components/src/dialog/dialog.ts b/packages/web-components/src/dialog/dialog.ts index d87d9b2fe9f5f3..b44bbe976acb15 100644 --- a/packages/web-components/src/dialog/dialog.ts +++ b/packages/web-components/src/dialog/dialog.ts @@ -110,8 +110,10 @@ export class Dialog extends FASTElement { if (newValue !== oldValue) { if (newValue && !oldValue && !this.dialog.open) { this.show(); + this.open = true; } else if (!newValue && oldValue && this.dialog.open) { this.hide(); + this.open = false; } } } @@ -159,9 +161,11 @@ export class Dialog extends FASTElement { Updates.enqueue(() => { if (this.modalType === DialogModalType.alert || this.modalType === DialogModalType.modal) { this.dialog.showModal(); + this.open = true; this.updateTrapFocus(true); } else if (this.modalType === DialogModalType.nonModal) { this.dialog.show(); + this.open = true; } this.onOpenChangeEvent(); }); @@ -174,6 +178,7 @@ export class Dialog extends FASTElement { */ public hide(dismissed: boolean = false): void { this.dialog.close(); + this.open = false; this.onOpenChangeEvent(dismissed); } From bd5b13cef7fc1a83d7bc2640ccc0dd475765cf9f Mon Sep 17 00:00:00 2001 From: brianchristopherbrady Date: Tue, 24 Oct 2023 11:27:00 -0700 Subject: [PATCH 43/45] dialog: sync open attribute --- .../src/dialog/dialog.stories.ts | 2 +- .../src/dialog/dialog.template.ts | 81 ++++++++++--------- packages/web-components/src/dialog/dialog.ts | 6 +- 3 files changed, 44 insertions(+), 45 deletions(-) diff --git a/packages/web-components/src/dialog/dialog.stories.ts b/packages/web-components/src/dialog/dialog.stories.ts index 4b20bc034dbe89..816f278f64c2f9 100644 --- a/packages/web-components/src/dialog/dialog.stories.ts +++ b/packages/web-components/src/dialog/dialog.stories.ts @@ -317,7 +317,7 @@ export const TwoColumnLayout = renderComponent(html` >
openDialog(e, 'dialog-twocolumn')}>Open Dialog - +
Welcome!
= html` - -
-
- - - ${when( - x => x.modalType === DialogModalType.nonModal && x.titleAction.length === 0 && !x.noTitleAction, - html` x.dismiss()} - ${ref('defaultTitleAction')} - >${dismissed16Regular}`, - )} -
-
- -
-
- + `; diff --git a/packages/web-components/src/dialog/dialog.ts b/packages/web-components/src/dialog/dialog.ts index b44bbe976acb15..4585bc3f28aa6a 100644 --- a/packages/web-components/src/dialog/dialog.ts +++ b/packages/web-components/src/dialog/dialog.ts @@ -108,12 +108,10 @@ export class Dialog extends FASTElement { */ public openChanged(oldValue: boolean, newValue: boolean): void { if (newValue !== oldValue) { - if (newValue && !oldValue && !this.dialog.open) { + if (newValue && !oldValue) { this.show(); - this.open = true; - } else if (!newValue && oldValue && this.dialog.open) { + } else if (!newValue && oldValue) { this.hide(); - this.open = false; } } } From 0a7ddc404b4891225105de47a2053b3d36f42bf4 Mon Sep 17 00:00:00 2001 From: brianchristopherbrady Date: Tue, 24 Oct 2023 12:24:55 -0700 Subject: [PATCH 44/45] dialog: updates storybook docs --- .../src/dialog/dialog.stories.ts | 340 +++++++++--------- 1 file changed, 179 insertions(+), 161 deletions(-) diff --git a/packages/web-components/src/dialog/dialog.stories.ts b/packages/web-components/src/dialog/dialog.stories.ts index 816f278f64c2f9..4435b669b5fd80 100644 --- a/packages/web-components/src/dialog/dialog.stories.ts +++ b/packages/web-components/src/dialog/dialog.stories.ts @@ -138,22 +138,24 @@ export const NonModal = renderComponent(html`
- A non-modal dialog by default presents no backdrop, allowing elements outside of the dialog to be interacted with. - A non-modal dialog will present by default a close button. + A non-modal dialog by default presents no backdrop, allowing elements outside of the dialog to be interacted with. + A non-modal dialog will present by default a close button.

Note: if an element outside of the dialog is focused then it will not be possible to close the dialog with the Escape key.


+ modal-type="non-modal" +
openDialog(e, 'dialog-nonmodal')}>Open Dialog
Non-modal

- A non-modal dialog by default presents no backdrop, allowing elements outside of the dialog to be interacted with. + A non-modal dialog by default presents no backdrop, allowing elements outside of the dialog to be interacted with. - A non-modal dialog will present by default a closeButton. + A non-moda dialog will present by default a closeButton.

Note: if an element outside of the dialog is focused then it will not be possible to close the dialog with the Escape key.

@@ -168,14 +170,16 @@ export const NonModal = renderComponent(html` export const Modal = renderComponent(html`
- - + +

A modal is a type of dialog that temporarily halts the main workflow to convey a significant message or require user interaction. By default, interactions such as clicking outside the dialog or pressing the Escape key will close the modal-dialog, resuming the user's interaction with the main content. - +


+ modal-type="modal" +
openDialog(e, 'dialog-modal')}>Open Dialog
Modal
@@ -196,19 +200,22 @@ export const Modal = renderComponent(html` export const Alert = renderComponent(html`
- - + +

An alert is a type of modal-dialog that interrupts the user's workflow to communicate an important message and - acquire a response. By default clicking on backdrop and pressing Escape will not dismiss an alert Dialog. - + acquire a response. By default clicking on backdrop and pressing Escape will not dismiss an alert dialog. +

+
+ modal-type="alert" +
openDialog(e, 'dialog-alert')}>Open Dialog
Alert
An alert is a type of modal-dialog that interrupts the user's workflow to communicate an important message and - acquire a response. By default clicking on backdrop and pressing Escape will not dismiss an alert Dialog. + acquire a response. By default clicking on backdrop and pressing Escape will not dismiss an alert dialog.

modal-type="alert" @@ -220,6 +227,154 @@ export const Alert = renderComponent(html`
`); +export const Actions = renderComponent(html` +
+

+ A dialog should have no more than + two + actions. +

+ + However, if required, you can populate the action slot with any number of buttons as needed. +
+ slot="action" +
+ openDialog(e, 'dialog-fluidactions')}>Open Dialog + +
Actions
+ + ${dismissed20Regular} + +
+ + A dialog should have no more than + two + footer actions. + +
+ + However, if required, you can populate the action slot with any number of buttons as needed. +
+ slot="action" +
+
+ + Something + Something Else + + Close Dialog + Something Else Entirely +
+
+`); + +export const TitleCustomAction = renderComponent(html` +
+ + By default a non-modal dialog renders a dismiss button with a close icon. + +
+ + + This slot can be customized to add a different kind of action, that it'll be available in any kind of dialog, + ignoring the modalType property, here's an example replacing the simple close icon with a fluent button using a + different icon. + + +
+ slot="title-action" +
+ openDialog(e, 'dialog-titlecustomaction')}>Open Dialog + +
Title Custom Action
+ + ${dismissCircle20Regular} + +
+ + By default a non-modal dialog renders a dismiss button with a close icon. + +
+ + + This slot can be customized to add a different kind of action, that it'll be available in any kind of + dialog, ignoring the modalType property, here's an example replacing the simple close icon with a fluent + button using a different icon. + + +
+ slot="title-action" +
+
+ + Close Dialog + Do Something +
+
+`); + +export const NoTitleAction = renderComponent(html` +
+

The no-title-action attribute can be provided to opt out of rendering any title action.

+
+ no-title-action +
+ openDialog(e, 'dialog-notitleaction')}>Open Dialog + +
No Title Action
+
+ +

The no-title-action attribute can be provided to opt out of rendering any title action.

+
+ no-title-action +
+
+ + Close Dialog + Do Something +
+
+`); + export const ControlledAndUncontrolled = renderComponent(html`
@@ -230,6 +385,8 @@ export const ControlledAndUncontrolled = renderComponent(html`
+ open +
openDialogControlled(e, 'dialog-controlled')}> Open Controlled Dialog @@ -237,12 +394,15 @@ export const ControlledAndUncontrolled = renderComponent(html`
- Utilize the show and hide methods to manage the dialog's visibility. This approach - allows the dialog to handle its state internally, giving you a direct and programmatic way to toggle its display - without relying on external attributes. + Utilize the show and hide methods to manage the dialog's visibility. This approach allows the dialog to handle + its state internally, giving you a direct and programmatic way to toggle its display without relying on external + attributes.
+ Dialog.show() + Dialog.hide() +
openDialog(e, 'dialog-uncontrolled')}>Open Uncontrolled Dialog
@@ -263,6 +423,7 @@ export const ControlledAndUncontrolled = renderComponent(html` attribute, ensuring the state is managed outside the component. + open

@@ -293,6 +454,9 @@ export const ControlledAndUncontrolled = renderComponent(html` display without relying on external attributes.
+
+ Dialog.show() + Dialog.hide()

@@ -470,149 +634,3 @@ export const ScrollingLongContent = renderComponent(html`
`); - -export const FooterAction = renderComponent(html` -
-

- A dialog should have no more than - two - footer actions. -

- - However, if required, you can populate the action slot with any number of buttons as needed. -
- openDialog(e, 'dialog-fluidactions')}>Open Dialog - -
Footer Action
- - ${dismissed20Regular} - -
- - A dialog should have no more than - two - footer actions. - -
- - However, if required, you can populate the action slot with any number of buttons as needed. -
-
- - Something - Something Else - - Close Dialog - Something Else Entirely -
-
-`); - -export const TitleCustomAction = renderComponent(html` -
- - By default if the dialog is set to modal-type='non-modal' a button with a close icon is provided - to close the dialog as action slot. - - -
- - - This slot can be customized to add a different kind of action, that it'll be available in any kind of dialog, - ignoring the modalType property, here's an example replacing the simple close icon with a fluent - button using a different icon. - - -
- openDialog(e, 'dialog-titlecustomaction')}>Open Dialog - -
Title Custom Action
- - ${dismissCircle20Regular} - -
- - By default if the dialog is set to modal-type='non-modal' a button with a close icon is - provided to close the dialog as action slot. - - -
- - - This slot can be customized to add a different kind of action, that it'll be available in any kind of - dialog, ignoring the modalType property, here's an example replacing the simple close icon with - a fluent button using a different icon. - - -
-
- - Close Dialog - Do Something -
-
-`); - -export const NoTitleAction = renderComponent(html` -
-

- The no-title-action attribute can be provided to opt out of rendering any title action. -

-
- openDialog(e, 'dialog-notitleaction')}>Open Dialog - -
No Title Action
-
- - The no-title-action attribute can be provided to opt out of rendering any title action. - -
-
- - Close Dialog - Do Something -
-
-`); From 25b97aeae07355bf420d5b73ef142c50f4084af1 Mon Sep 17 00:00:00 2001 From: brianchristopherbrady Date: Tue, 24 Oct 2023 12:28:40 -0700 Subject: [PATCH 45/45] dialog: updates readme docs --- packages/web-components/src/dialog/README.md | 28 +++++++------------- 1 file changed, 10 insertions(+), 18 deletions(-) diff --git a/packages/web-components/src/dialog/README.md b/packages/web-components/src/dialog/README.md index 7d80528d44c4d5..df863504dd81f7 100644 --- a/packages/web-components/src/dialog/README.md +++ b/packages/web-components/src/dialog/README.md @@ -28,10 +28,11 @@ Fluent WC3 Dialog has feature parity with the Fluent UI React 9 Dialog implement Dialog - Content + Default Content - Do Something + Do Something + Close ``` @@ -42,7 +43,6 @@ Fluent WC3 Dialog has feature parity with the Fluent UI React 9 Dialog implement | `modal-type` | public | `DialogModalType` | `DialogModalType.modal` | Indicates that the type of modal to render. | | `open` | public | `boolean` | `false` | Controls the open state of the dialog | | `no-title-action` | public | `boolean` | `false` | Used to set whether the default title action is rendered. | -| `change-focus` | public | `string` | `undefined` | Used to set id of desired focus target. | | `aria-labelledby` | public | `string` | `undefined` | optional based on implementation\*\* | | `aria-describedby` | public | `string` | `undefined` | optional based on implementation\*\* | | `aria-label ` | public | `string` | `undefined` | optional based on implementation\*\* | @@ -62,12 +62,12 @@ Fluent WC3 Dialog has feature parity with the Fluent UI React 9 Dialog implement ### **Slots** -| Name | Description | -| --------------- | ---------------------------------------------------------- | -| `title` | slot for title content | -| `title-action` | slot for close button | -| | default slot for content rendered between title and footer | -| `footer-action` | slot for actions content | +| Name | Description | +| -------------- | ---------------------------------------------------------- | +| `title` | slot for title content | +| `title-action` | slot for close button | +| | default slot for content rendered between title and footer | +| `action` | slot for actions content | ### **Events** @@ -88,12 +88,4 @@ Fluent WC3 Dialog has feature parity with the Fluent UI React 9 Dialog implement | `` | `dialog::backdrop` | In the React version of our components, the DialogSurface component is used as part of the composite Dialog component to represent the dimmed background of the dialog.
The Web Component version utilizes the HTML dialog ::backdrop pseudoelement. | | `` | `slot: title` | In the React version of our components, the component is used to implement the title of the dialog.
In the Web Component version, the title is provided through the title slot. | | `` | `slot: title-action` | In the React version of our components, the component the DialogTitles action prop.
In the Web Component version, the title action is provided through the Dialogs title-action slot | -| `` | `slot: footer-action` | In the React version of our components, the component is used to implement the actions within the dialog.
In the Web Component version, actions are passsed through the `actions` slot | - -
- -**Attribute and prop Mapping** - -| Fluent UI React 9 | Fluent Web Components 3 | Description of difference | -| ------------------------------------ | ----------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------- | -| use effect to customize focus target | `change-focus` | Changing the default focused element can be done in an effect. In FUIWC3, the id of the desired target to focus can be passed through the change-focus slot | +| `` | `slot: action` | In the React version of our components, the component is used to implement the actions within the dialog.
In the Web Component version, actions are passsed through the `action` slot |