diff --git a/common/changes/@uifabric/fabric-website/mergeStyles-Dialog-round2_2018-03-08-01-38.json b/common/changes/@uifabric/fabric-website/mergeStyles-Dialog-round2_2018-03-08-01-38.json new file mode 100644 index 0000000000000..8f4224c4cc65b --- /dev/null +++ b/common/changes/@uifabric/fabric-website/mergeStyles-Dialog-round2_2018-03-08-01-38.json @@ -0,0 +1,11 @@ +{ + "changes": [ + { + "comment": "", + "packageName": "@uifabric/fabric-website", + "type": "none" + } + ], + "packageName": "@uifabric/fabric-website", + "email": "v-jojanz@microsoft.com" +} \ No newline at end of file diff --git a/common/changes/@uifabric/utilities/mergeStyles-Dialog-round2_2018-03-08-01-38.json b/common/changes/@uifabric/utilities/mergeStyles-Dialog-round2_2018-03-08-01-38.json new file mode 100644 index 0000000000000..46b0ccfc46b68 --- /dev/null +++ b/common/changes/@uifabric/utilities/mergeStyles-Dialog-round2_2018-03-08-01-38.json @@ -0,0 +1,11 @@ +{ + "changes": [ + { + "packageName": "@uifabric/utilities", + "comment": "Add hoistStatics function to withResponsiveMode decorator.", + "type": "minor" + } + ], + "packageName": "@uifabric/utilities", + "email": "v-jojanz@microsoft.com" +} \ No newline at end of file diff --git a/common/changes/office-ui-fabric-react/mergeStyles-Dialog-round2_2018-03-02-01-05.json b/common/changes/office-ui-fabric-react/mergeStyles-Dialog-round2_2018-03-02-01-05.json new file mode 100644 index 0000000000000..8105d557df85b --- /dev/null +++ b/common/changes/office-ui-fabric-react/mergeStyles-Dialog-round2_2018-03-02-01-05.json @@ -0,0 +1,11 @@ +{ + "changes": [ + { + "packageName": "office-ui-fabric-react", + "comment": "Dialog: convert to mergeStyles part 2.", + "type": "minor" + } + ], + "packageName": "office-ui-fabric-react", + "email": "v-jojanz@microsoft.com" +} \ No newline at end of file diff --git a/packages/office-ui-fabric-react/src/components/Dialog/Dialog.base.tsx b/packages/office-ui-fabric-react/src/components/Dialog/Dialog.base.tsx index dc8434d5d3f6d..54e5220ea7ddb 100644 --- a/packages/office-ui-fabric-react/src/components/Dialog/Dialog.base.tsx +++ b/packages/office-ui-fabric-react/src/components/Dialog/Dialog.base.tsx @@ -1,15 +1,20 @@ import * as React from 'react'; import { BaseComponent, - css, + classNamesFunction, + customizable, getId } from '../../Utilities'; -import { IDialogProps } from './Dialog.types'; +import { + IDialogProps, + IDialogStyleProps, + IDialogStyles, +} from './Dialog.types'; import { DialogType, IDialogContentProps } from './DialogContent.types'; import { Modal, IModalProps } from '../../Modal'; import { withResponsiveMode } from '../../utilities/decorators/withResponsiveMode'; -import * as stylesImport from './Dialog.scss'; -const styles: any = stylesImport; + +const getClassNames = classNamesFunction(); import { DialogContent } from './DialogContent'; @@ -26,6 +31,7 @@ const DefaultDialogContentProps: IDialogContentProps = { topButtonsProps: [], }; +@customizable('Dialog', ['theme']) @withResponsiveMode export class DialogBase extends BaseComponent { public static defaultProps: IDialogProps = { @@ -62,26 +68,28 @@ export class DialogBase extends BaseComponent { public render() { const { + className, + containerClassName, + contentClassName, elementToFocusOnDismiss, firstFocusableSelector, forceFocusInsideTrap, + getStyles, + hidden, ignoreExternalFocusing, isBlocking, isClickableOutsideFocusTrap, isDarkOverlay, isOpen, - className, onDismiss, onDismissed, onLayerDidMount, responsiveMode, subText, + theme, title, - type, - contentClassName, topButtonsProps, - containerClassName, - hidden + type, } = this.props; const modalProps = { @@ -91,9 +99,16 @@ export class DialogBase extends BaseComponent { const dialogContentProps: IDialogContentProps = { ...DefaultDialogContentProps, - ...this.props.dialogContentProps + ...this.props.dialogContentProps, }; + const classNames = getClassNames(getStyles!, { + theme: theme!, + className: className || modalProps!.className, + containerClassName: containerClassName || modalProps!.containerClassName, + hidden, + }); + return ( { isDarkOverlay={ isDarkOverlay !== undefined ? isDarkOverlay : modalProps!.isDarkOverlay } isBlocking={ isBlocking !== undefined ? isBlocking : modalProps!.isBlocking } isOpen={ isOpen !== undefined ? isOpen : !hidden } - className={ css('ms-Dialog', className ? className : modalProps!.className) } - containerClassName={ css(styles.main, containerClassName ? containerClassName : modalProps!.containerClassName) } + className={ classNames.root } + containerClassName={ classNames.main } onDismiss={ onDismiss ? onDismiss : modalProps!.onDismiss } subtitleAriaId={ this._getSubTextId() } titleAriaId={ this._getTitleTextId() } @@ -123,7 +138,7 @@ export class DialogBase extends BaseComponent { topButtonsProps={ topButtonsProps ? topButtonsProps : dialogContentProps!.topButtonsProps } type={ type !== undefined ? type : dialogContentProps!.type } onDismiss={ onDismiss ? onDismiss : dialogContentProps!.onDismiss } - className={ css(contentClassName ? contentClassName : dialogContentProps!.className) } + className={ contentClassName || dialogContentProps!.className } { ...dialogContentProps } > { this.props.children } diff --git a/packages/office-ui-fabric-react/src/components/Dialog/Dialog.scss b/packages/office-ui-fabric-react/src/components/Dialog/Dialog.scss deleted file mode 100644 index aaebc582a2d50..0000000000000 --- a/packages/office-ui-fabric-react/src/components/Dialog/Dialog.scss +++ /dev/null @@ -1,150 +0,0 @@ -@import '../../common/common'; - -// Copyright (c) Microsoft. All rights reserved. Licensed under the MIT license. See LICENSE in the project root for license information. - -// -// Office UI Fabric -// -------------------------------------------------- -// Dialog styles - -$Dialog-lgHeader-backgroundColor: $ms-color-themePrimary; -$Dialog-default-min-width: 288px; -$Dialog-default-max-width: 340px; - -// State: The dialog is open -.isOpen { - display: flex; -} - -// The actual dialog element -.main { - width: $Dialog-default-min-width; -} - -// Close button, hidden by default -.button.isClose { - :global(.ms-Icon.ms-Icon--Cancel) { - color: $ms-color-neutralSecondary; - font-size: 16px; - } -} - -.inner { - padding: 0 28px 20px; -} - -.header { - position: relative; - width: 100%; - box-sizing: border-box; -} - -.title { - margin: 0; - @include ms-font-xl; - color: $ms-color-neutralPrimary; - @include ms-padding(20px, 36px, 20px, 28px); -} - -.topButton { - display: flex; - flex-direction: row; - flex-wrap: nowrap; - position: absolute; - top: 0; - @include ms-right(0); - @include ms-padding(12px, 12px, 0, 0); - > * { - flex: 0 0 auto; - } -} - -.content { - position: relative; - width: 100%; - - // Add margin bottom between compound buttons - :global(.ms-Button.ms-Button--compound) { - margin-bottom: 20px; - - &:last-child { - margin-bottom: 0; - } - } -} - -.subText { - margin: 0 0 20px 0; - padding-top: 8px; - @include ms-font-s; - color: $ms-color-neutralPrimary; - font-weight: $ms-font-weight-semilight; - line-height: 1.5; - word-wrap: break-word; -} - -.actions { - position: relative; - width: 100%; - min-height: 24px; - line-height: 24px; - margin: 20px 0 0; - font-size: 0; - - :global(.ms-Button) { - line-height: normal; - } -} - -// Negative margin to needed to compensate for symmetric -// padding between action elements. -.actionsRight { - @include ms-text-align(right); - @include ms-margin-right(-4px); - font-size: 0; - - // Reset spacing for first button - .action { - margin: 0px 4px; - } -} - -//= Modifier: Multiline button dialog -// -.isMultiline { - .title { - font-size: $ms-font-size-xxl; - } - - .inner { - padding: 0 20px 20px; - } -} - -//= Modifier: Large header dialog -// -.isLargeHeader { - .header { - background-color: $Dialog-lgHeader-backgroundColor; - } - - .title { - @include ms-font-xxl; - color: $ms-color-white; - padding: 26px 28px 28px; - margin-bottom: 8px; - } - - .subText { - font-size: $ms-font-size-m; - } -} - -@media (min-width: $ms-screen-min-md) { - // Allow wider dialog on larger screens - .main { - width: auto; - min-width: $Dialog-default-min-width; - max-width: $Dialog-default-max-width; - } -} diff --git a/packages/office-ui-fabric-react/src/components/Dialog/Dialog.styles.ts b/packages/office-ui-fabric-react/src/components/Dialog/Dialog.styles.ts index 9e56e1011cae4..990aa517aace8 100644 --- a/packages/office-ui-fabric-react/src/components/Dialog/Dialog.styles.ts +++ b/packages/office-ui-fabric-react/src/components/Dialog/Dialog.styles.ts @@ -1,17 +1,39 @@ import { IDialogStyleProps, IDialogStyles } from './Dialog.types'; +import { + ScreenWidthMinMedium, +} from '../../Styling'; export const getStyles = ( props: IDialogStyleProps ): IDialogStyles => { + const { + className, + containerClassName, + dialogDefaultMinWidth = '288px', + dialogDefaultMaxWidth = '340px', + hidden, + } = props; return ({ root: [ 'ms-Dialog', - { - // Insert css properties - } + className, ], - // Insert className styles + main: [ + { + width: dialogDefaultMinWidth, + + selectors: { + [`@media (min-width: ${ScreenWidthMinMedium}px)`]: { + width: 'auto', + maxWidth: dialogDefaultMaxWidth, + minWidth: dialogDefaultMinWidth, + } + } + }, + !hidden && { display: 'flex' }, + containerClassName, + ] }); }; diff --git a/packages/office-ui-fabric-react/src/components/Dialog/Dialog.types.ts b/packages/office-ui-fabric-react/src/components/Dialog/Dialog.types.ts index 5a8a95acb6e7b..2803f1d35407f 100644 --- a/packages/office-ui-fabric-react/src/components/Dialog/Dialog.types.ts +++ b/packages/office-ui-fabric-react/src/components/Dialog/Dialog.types.ts @@ -157,7 +157,35 @@ export interface IDialogStyleProps { */ className?: string; - // Insert Dialog style props below + /** + * Optional override for container class + * @deprecated Pass through via modalProps.className instead + */ + containerClassName?: string; + + /** + * Optional override content class + * @deprecated Pass through via dialogContentProps instead as className + */ + contentClassName?: string; + + /** + * Whether the dialog is hidden. + * @default false + */ + hidden?: boolean; + + /** + * Default min-width for the dialog box. + * @defaultvalue '288px' + */ + dialogDefaultMinWidth?: string; + + /** + * Default max-width for the dialog box. + * @defaultvalue '340px' + */ + dialogDefaultMaxWidth?: string; } export interface IDialogStyles { @@ -165,6 +193,5 @@ export interface IDialogStyles { * Style for the root element. */ root: IStyle; - - // Insert Dialog classNames below + main: IStyle; } \ No newline at end of file diff --git a/packages/office-ui-fabric-react/src/components/Dialog/DialogContent.base.tsx b/packages/office-ui-fabric-react/src/components/Dialog/DialogContent.base.tsx index f5e48022f320b..a956ee6dec949 100644 --- a/packages/office-ui-fabric-react/src/components/Dialog/DialogContent.base.tsx +++ b/packages/office-ui-fabric-react/src/components/Dialog/DialogContent.base.tsx @@ -1,15 +1,22 @@ import * as React from 'react'; import { BaseComponent, - css, + classNamesFunction, + customizable, } from '../../Utilities'; -import { IDialogContentProps, DialogType } from './DialogContent.types'; +import { + DialogType, + IDialogContentProps, + IDialogContentStyleProps, + IDialogContentStyles, +} from './DialogContent.types'; import { IconButton } from '../../Button'; import { DialogFooter } from './DialogFooter'; import { withResponsiveMode } from '../../utilities/decorators/withResponsiveMode'; -import * as stylesImport from './Dialog.scss'; -const styles: any = stylesImport; +const getClassNames = classNamesFunction(); + +@customizable('DialogContent', ['theme']) @withResponsiveMode export class DialogContentBase extends BaseComponent { @@ -27,40 +34,42 @@ export class DialogContentBase extends BaseComponent { public render() { const { showCloseButton, + className, closeButtonAriaLabel, onDismiss, subTextId, subText, titleId, title, - type + type, + getStyles, + theme, } = this.props; + const classNames = getClassNames(getStyles!, { + theme: theme!, + className, + isLargeHeader: type === DialogType.largeHeader, + isClose: type === DialogType.close, + }); + const groupings = this._groupChildren(); let subTextContent; if (subText) { - subTextContent =

{ subText }

; + subTextContent =

{ subText }

; } - const contentClassName = css(this.props.className, { - ['ms-Dialog--lgHeader ' + styles.isLargeHeader]: type === DialogType.largeHeader, - ['ms-Dialog--close ' + styles.isClose]: type === DialogType.close, - }); - return ( -
-
-

{ title }

-
+
+
+

{ title }

+
{ this.props.topButtonsProps!.map((props) => ( )) } { (type === DialogType.close || (showCloseButton && type !== DialogType.largeHeader)) && { }
-
-
+
+
{ subTextContent } { groupings.contents }
diff --git a/packages/office-ui-fabric-react/src/components/Dialog/DialogContent.styles.ts b/packages/office-ui-fabric-react/src/components/Dialog/DialogContent.styles.ts index 45bb22f518319..c010c92d73c57 100644 --- a/packages/office-ui-fabric-react/src/components/Dialog/DialogContent.styles.ts +++ b/packages/office-ui-fabric-react/src/components/Dialog/DialogContent.styles.ts @@ -1,18 +1,137 @@ -import { IDialogContentStyleProps, IDialogContentStyles } from './DialogContent.types'; +import { + IDialogContentStyleProps, + IDialogContentStyles, +} from './DialogContent.types'; +import { + FontWeights, +} from '../../Styling'; export const getStyles = ( props: IDialogContentStyleProps ): IDialogContentStyles => { + const { + className, + theme, + isLargeHeader, + isClose, + hidden, + isMultiline, + } = props; + + const { palette, fonts } = theme; return ({ content: [ - 'ms-DialogContent', + isLargeHeader && 'ms-Dialog-lgHeader', + isClose && 'ms-Dialog--close', + className + ], + + subText: [ + 'ms-Dialog-subText', + isLargeHeader ? fonts.medium : fonts.small, + { + margin: '0 0 20px 0', + paddingTop: '8px', + color: palette.neutralPrimary, + lineHeight: '1.5', + wordWrap: 'break-word', + fontWeight: FontWeights.semilight, + }, + ], + + header: [ + 'ms-Dialog-header', { - // Insert css properties + position: 'relative', + width: '100%', + boxSizing: 'border-box', + }, + isLargeHeader && [ + 'ms-Dialog--lgHeader', + { + backgroundColor: palette.themePrimary, + } + ], + isClose && 'ms-Dialog--close', + ], + + button: [ + 'ms-Dialog-button', + 'ms-Dialog-button--close', + hidden && { + selectors: { + '.ms-Icon.ms-Icon--Cancel': { + color: palette.neutralSecondary, + fontSize: '16px', + } + } + } + ], + inner: [ + 'ms-Dialog-inner', + { + padding: isMultiline ? '0 20px 20px' : '0 28px 20px', } ], - // Insert className styles + innerContent: [ + 'ms-Dialog-content', + { + position: 'relative', + width: '100%', + + selectors: { + '.ms-Button.ms-Button--compount': { + marginBottom: '20px', + + selectors: { + '&:last-child': { + marginBottom: '0', + } + } + } + } + }, + className + ], + + title: [ + 'ms-Dialog-title', + { + color: palette.neutralPrimary, + margin: '0', + padding: '20px 36px 20px 28px', + }, + fonts.xLarge, + isLargeHeader && [ + { + color: palette.white, + marginBottom: '8px', + padding: '26px 28px 28px', + }, + fonts.xxLarge + ], + isMultiline && fonts.xxLarge, + ], + + topButton: [ + { + display: 'flex', + flexDirection: 'row', + flexWrap: 'nowrap', + position: 'absolute', + top: '0', + right: '0', + padding: '12px 12px 0 0', + + selectors: { + '> *': { + flex: '0 0 auto', + } + } + } + ], }); }; diff --git a/packages/office-ui-fabric-react/src/components/Dialog/DialogContent.types.ts b/packages/office-ui-fabric-react/src/components/Dialog/DialogContent.types.ts index 927151886a8d3..9aba2f5ced9a8 100644 --- a/packages/office-ui-fabric-react/src/components/Dialog/DialogContent.types.ts +++ b/packages/office-ui-fabric-react/src/components/Dialog/DialogContent.types.ts @@ -26,6 +26,11 @@ export interface IDialogContentProps extends React.Props { */ theme?: ITheme; + /** + * Is inside a multiline wrapper + */ + isMultiline?: boolean; + /** * Show an 'x' close button in the upper-right corner */ @@ -104,14 +109,26 @@ export interface IDialogContentStyleProps { */ className?: string; - // Insert DialogContent style props below + isLargeHeader?: boolean; + isClose?: boolean; + hidden?: boolean; + + /** + * Is inside a multiline wrapper + */ + isMultiline?: boolean; } export interface IDialogContentStyles { /** - * Style for the root element. + * Style for the content element. */ - content?: IStyle; - - // Insert DialogContent classNames below + content: IStyle; + subText: IStyle; + header: IStyle; + button: IStyle; + inner: IStyle; + innerContent: IStyle; + title: IStyle; + topButton: IStyle; } \ No newline at end of file diff --git a/packages/office-ui-fabric-react/src/components/Dialog/DialogFooter.base.tsx b/packages/office-ui-fabric-react/src/components/Dialog/DialogFooter.base.tsx index 7583d6fb5a190..ca9db4ff5bafa 100644 --- a/packages/office-ui-fabric-react/src/components/Dialog/DialogFooter.base.tsx +++ b/packages/office-ui-fabric-react/src/components/Dialog/DialogFooter.base.tsx @@ -1,13 +1,37 @@ import * as React from 'react'; -import { BaseComponent, css } from '../../Utilities'; -import * as stylesImport from './Dialog.scss'; -const styles: any = stylesImport; +import { + IDialogFooterProps, + IDialogFooterStyleProps, + IDialogFooterStyles, +} from './DialogFooter.types'; +import { + BaseComponent, + classNamesFunction, + customizable, + IClassNames +} from '../../Utilities'; + +const getClassNames = classNamesFunction(); + +@customizable('DialogFooter', ['theme']) +export class DialogFooterBase extends BaseComponent { + private _classNames: IClassNames; -export class DialogFooterBase extends BaseComponent { public render() { + const { + className, + getStyles, + theme + } = this.props; + + this._classNames = getClassNames(getStyles!, { + theme: theme!, + className + }); + return ( -
-
+
+
{ this._renderChildrenAsActions() }
@@ -16,7 +40,7 @@ export class DialogFooterBase extends BaseComponent { private _renderChildrenAsActions() { return React.Children.map(this.props.children, child => - child && { child } + child && { child } ); } } diff --git a/packages/office-ui-fabric-react/src/components/Dialog/DialogFooter.styles.ts b/packages/office-ui-fabric-react/src/components/Dialog/DialogFooter.styles.ts index c530d830a6579..f8277cd04c6ba 100644 --- a/packages/office-ui-fabric-react/src/components/Dialog/DialogFooter.styles.ts +++ b/packages/office-ui-fabric-react/src/components/Dialog/DialogFooter.styles.ts @@ -3,15 +3,47 @@ import { IDialogFooterStyleProps, IDialogFooterStyles } from './DialogFooter.typ export const getStyles = ( props: IDialogFooterStyleProps ): IDialogFooterStyles => { + const { + className, + } = props; + return ({ actions: [ 'ms-Dialog-actions', { - // Insert css properties + position: 'relative', + width: '100%', + minHeight: '24px', + lineHeight: '24px', + margin: '20px 0 0', + fontSize: '0', - } + selectors: { + '.ms-Button': { + lineHeight: 'normal', + } + } + }, + className + ], + + action: [ + 'ms-Dialog-action', ], - // Insert className styles + actionsRight: [ + 'ms-Dialog-actionsRight', + { + textAlign: 'right', + marginRight: '-4px', + fontSize: '0', + + selectors: { + '$action': { + margin: '0 4px', + } + } + } + ] }); }; diff --git a/packages/office-ui-fabric-react/src/components/Dialog/DialogFooter.types.ts b/packages/office-ui-fabric-react/src/components/Dialog/DialogFooter.types.ts index 2882c8ac10a15..47fa490d10f58 100644 --- a/packages/office-ui-fabric-react/src/components/Dialog/DialogFooter.types.ts +++ b/packages/office-ui-fabric-react/src/components/Dialog/DialogFooter.types.ts @@ -20,12 +20,9 @@ export interface IDialogFooterProps extends React.Props { theme?: ITheme; /** - * Additional css class to apply to the DialogFooter - * @defaultvalue undefined - */ + * Optional override class name + */ className?: string; - - // Insert DialogFooter props below } export interface IDialogFooterStyleProps { @@ -35,18 +32,17 @@ export interface IDialogFooterStyleProps { theme: ITheme; /** - * Accept custom classNames - */ + * Optional override class name + */ className?: string; - - // Insert DialogFooter style props below } export interface IDialogFooterStyles { /** - * Style for the root element. + * Style for the actions element. */ - actions?: IStyle; + actions: IStyle; - // Insert DialogFooter classNames below + actionsRight: IStyle; + action: IStyle; } \ No newline at end of file diff --git a/packages/office-ui-fabric-react/src/components/Dialog/__snapshots__/Dialog.test.tsx.snap b/packages/office-ui-fabric-react/src/components/Dialog/__snapshots__/Dialog.test.tsx.snap index fdd5a77567304..1d89aeb736a69 100644 --- a/packages/office-ui-fabric-react/src/components/Dialog/__snapshots__/Dialog.test.tsx.snap +++ b/packages/office-ui-fabric-react/src/components/Dialog/__snapshots__/Dialog.test.tsx.snap @@ -2,25 +2,84 @@ exports[`Dialog renders Dialog correctly 1`] = `

* { + flex: 0 0 auto; + } />
diff --git a/packages/office-ui-fabric-react/src/utilities/decorators/withResponsiveMode.tsx b/packages/office-ui-fabric-react/src/utilities/decorators/withResponsiveMode.tsx index c192b013b4d83..73671d6be4c4e 100644 --- a/packages/office-ui-fabric-react/src/utilities/decorators/withResponsiveMode.tsx +++ b/packages/office-ui-fabric-react/src/utilities/decorators/withResponsiveMode.tsx @@ -35,7 +35,7 @@ export function setResponsiveMode(responsiveMode: ResponsiveMode | undefined) { export function withResponsiveMode(ComposedComponent: (new (props: TProps, ...args: any[]) => React.Component)): any { - return class WithResponsiveMode extends BaseDecorator { + const resultClass = class WithResponsiveMode extends BaseDecorator { constructor(props: TProps) { super(props); @@ -96,5 +96,18 @@ export function withResponsiveMode(source: TSource, dest: TDest): TDest { + for (const name in source) { + if (source.hasOwnProperty(name)) { + // tslint:disable-next-line:no-any + (dest as any)[name] = source[name]; + } + } + + return dest; }