diff --git a/.vscode/launch.json b/.vscode/launch.json index 13615cfafff03e..43d411bfaede0d 100644 --- a/.vscode/launch.json +++ b/.vscode/launch.json @@ -22,10 +22,27 @@ "outDir": null }, { - "name": "Attach", + "name": "Run ssr tests", "type": "node", - "request": "attach", - "port": 5858 - } + "request": "launch", + "program": "${workspaceRoot}/apps/ssr-tests/node_modules/mocha/bin/_mocha", + "stopOnEntry": true, + "args": [ + "--debug", + "dist/test-bundle.js" + ], + "cwd": "${workspaceRoot}/apps/ssr-tests", + "runtimeExecutable": null, + "runtimeArgs": [ + "--nolazy", + "--debug" + ], + "env": { + "NODE_ENV": "development" + }, + "externalConsole": false, + "sourceMaps": false, + "outDir": null + }, ] } \ No newline at end of file diff --git a/apps/fabric-website/src/pages/GetStarted/GetStartedPage.tsx b/apps/fabric-website/src/pages/GetStarted/GetStartedPage.tsx index b11d8ce4a25d57..7f60bab4977646 100644 --- a/apps/fabric-website/src/pages/GetStarted/GetStartedPage.tsx +++ b/apps/fabric-website/src/pages/GetStarted/GetStartedPage.tsx @@ -128,9 +128,9 @@ export class GetStartedPage extends React.Component { { `import * as React from 'react'; import * as ReactDOM from 'react-dom'; -import { Button } from 'office-ui-fabric-react/lib/Button'; +import { DefaultButton } from 'office-ui-fabric-react/lib/Button'; -const MyPage = () => (
); +const MyPage = () => (
I am a button.
); ReactDOM.render(, document.body.firstChild);` } diff --git a/apps/ssr-tests/package.json b/apps/ssr-tests/package.json index 1f428261db9261..bda0cc3ad58398 100644 --- a/apps/ssr-tests/package.json +++ b/apps/ssr-tests/package.json @@ -9,8 +9,10 @@ "url": "https://github.com/OfficeDev/office-ui-fabric-react" }, "scripts": { - "build": "node ./node_modules/mocha/bin/mocha && echo Ignored parameters: ", - "test": "node ./node_modules/mocha/bin/mocha && echo Ignored parameters: ", + "_webpack": "node ./node_modules/webpack/bin/webpack --config webpack.config.js", + "_mocha": "node ./node_modules/mocha/bin/_mocha dist/ssr-tests.js", + "build": "npm run _webpack", + "test": "npm run _webpack && npm run _mocha", "clean": "", "start": "" }, @@ -27,7 +29,11 @@ "raw-loader": "^0.5.1", "react": "^15.4.2", "react-addons-test-utils": "^15.4.2", - "react-dom": "^15.4.2" + "react-dom": "^15.4.2", + "webpack": "^2.4.1", + "webpack-node-externals": "^1.5.4" }, - "dependencies": {} + "dependencies": { + "es6-promise": "^4.1.0" + } } \ No newline at end of file diff --git a/apps/ssr-tests/test/test.js b/apps/ssr-tests/test/test.js index a949a89cd40d05..f913ec8b14ef55 100644 --- a/apps/ssr-tests/test/test.js +++ b/apps/ssr-tests/test/test.js @@ -17,24 +17,22 @@ responsiveLib.setResponsiveMode(responsiveLib.ResponsiveMode.large); let React = require('react'); let ReactDOMServer = require('react-dom/server'); -let AppDefinition = require('fabric-examples/lib/AppDefinition').AppDefinition; +let AppDefinition = require('office-ui-fabric-react/lib/demo/AppDefinition').AppDefinition; describe('Fabric components', () => { for (let i = 0; i < AppDefinition.examplePages.length; i++) { let links = AppDefinition.examplePages[i].links; - for (let j = 0; j < links.length; j++) { - let componentName = links[j].key; + let { key, component } = links[j]; - testRender(componentName); + testRender(key, component); } } }); -function testRender(componentName) { + +function testRender(componentName, component) { it(`${componentName} can render in a server environment`, (done) => { - let componentPath = `fabric-examples/lib/pages/${componentName}Page/${componentName}Page`; - let component = require(componentPath)[componentName + 'Page']; let elem = React.createElement(component); try { diff --git a/apps/ssr-tests/webpack.config.js b/apps/ssr-tests/webpack.config.js new file mode 100644 index 00000000000000..8ffc5cee6e26aa --- /dev/null +++ b/apps/ssr-tests/webpack.config.js @@ -0,0 +1,45 @@ +let path = require('path'); +let nodeExternals = require('webpack-node-externals'); + +module.exports = { + entry: './test/test.js', + + output: { + filename: 'dist/ssr-tests.js', + }, + + target: 'node', + + externals: [ + // nodeExternals() + "vertx" + ], + + node: { + fs: 'empty' + }, + + resolve: { + alias: { + 'office-ui-fabric-react/src': path.join(__dirname, '../../packages/office-ui-fabric-react/src'), + 'office-ui-fabric-react/lib': path.join(__dirname, '../../packages/office-ui-fabric-react/lib'), + 'Props.ts.js': 'Props' + }, + extensions: ['.js', '.tsx'] + }, + + devtool: 'source-map', + + devServer: { + inline: true, + port: 4321 + }, + + module: { + loaders: [ + ] + }, + + plugins: [ + ] +} diff --git a/apps/todo-app/src/components/TodoForm.tsx b/apps/todo-app/src/components/TodoForm.tsx index 86554e1065c9d1..46b1ae6ee47efe 100644 --- a/apps/todo-app/src/components/TodoForm.tsx +++ b/apps/todo-app/src/components/TodoForm.tsx @@ -8,11 +8,11 @@ const styles: any = stylesImport; import strings from './../strings'; /** - * The form component used for adding new item to the list. + * The form component used for adding new item to the list. It uses fabric-react components + * TextField and PrimaryButton. * - * It uses fabric-react component + implements let { isChecked } = this.state; let stateText = isChecked ? onText : offText; const ariaLabel = isChecked ? onAriaLabel : offAriaLabel; - const toggleNativeProps = getNativeProps(this.props, inputProperties); + const toggleNativeProps = getNativeProps(this.props, inputProperties, ['defaultChecked']); return (
implements ref={ (c): HTMLInputElement => this._toggleInput = c } type='checkbox' id={ this._id } + onChange={ () => { /* no-op */ } } { ...toggleNativeProps } className={ styles.invisibleToggle } name={ this._id } diff --git a/packages/office-ui-fabric-react/src/demo/AppDefinition.tsx b/packages/office-ui-fabric-react/src/demo/AppDefinition.tsx index b6014a63f0898d..fc8a48b522e64a 100644 --- a/packages/office-ui-fabric-react/src/demo/AppDefinition.tsx +++ b/packages/office-ui-fabric-react/src/demo/AppDefinition.tsx @@ -17,211 +17,211 @@ export const AppDefinition: IAppDefinition = { { links: [ { - getComponent: cb => cb(require('../components/Breadcrumb/BreadcrumbPage').BreadcrumbPage), + component: require('../components/Breadcrumb/BreadcrumbPage').BreadcrumbPage, key: 'Breadcrumb', name: 'Breadcrumb', url: '#/examples/breadcrumb' }, { - getComponent: cb => cb(require('../components/Button/ButtonPage').ButtonPage), + component: require('../components/Button/ButtonPage').ButtonPage, key: 'Button', name: 'Button', url: '#/examples/button' }, { - getComponent: cb => cb(require('../components/Calendar/CalendarPage').CalendarPage), + component: require('../components/Calendar/CalendarPage').CalendarPage, key: 'Calendar', name: 'Calendar', url: '#/examples/calendar' }, { - getComponent: cb => cb(require('../components/Callout/CalloutPage').CalloutPage), + component: require('../components/Callout/CalloutPage').CalloutPage, key: 'Callout', name: 'Callout', url: '#/examples/callout' }, { - getComponent: cb => cb(require('../components/Checkbox/CheckboxPage').CheckboxPage), + component: require('../components/Checkbox/CheckboxPage').CheckboxPage, key: 'Checkbox', name: 'Checkbox', url: '#/examples/checkbox' }, { - getComponent: cb => cb(require('../components/ChoiceGroup/ChoiceGroupPage').ChoiceGroupPage), + component: require('../components/ChoiceGroup/ChoiceGroupPage').ChoiceGroupPage, key: 'ChoiceGroup', name: 'ChoiceGroup', url: '#/examples/choicegroup' }, { - getComponent: cb => cb(require('../components/CommandBar/CommandBarPage').CommandBarPage), + component: require('../components/CommandBar/CommandBarPage').CommandBarPage, key: 'CommandBar', name: 'CommandBar', url: '#/examples/commandbar' }, { - getComponent: cb => cb(require('../components/ContextualMenu/ContextualMenuPage').ContextualMenuPage), + component: require('../components/ContextualMenu/ContextualMenuPage').ContextualMenuPage, key: 'ContextualMenu', name: 'ContextualMenu', url: '#/examples/contextmenu' }, { - getComponent: cb => cb(require('../components/DatePicker/DatePickerPage').DatePickerPage), + component: require('../components/DatePicker/DatePickerPage').DatePickerPage, key: 'DatePicker', name: 'DatePicker', url: '#/examples/datepicker' }, { - getComponent: cb => cb(require('../components/DetailsList/DetailsListPage').DetailsListPage), + component: require('../components/DetailsList/DetailsListPage').DetailsListPage, key: 'DetailsList', name: 'DetailsList', url: '#/examples/detailslist' }, { - getComponent: cb => cb(require('../components/Dialog/DialogPage').DialogPage), + component: require('../components/Dialog/DialogPage').DialogPage, key: 'Dialog', name: 'Dialog', url: '#/examples/dialog' }, { - getComponent: cb => cb(require('../components/DocumentCard/DocumentCardPage').DocumentCardPage), + component: require('../components/DocumentCard/DocumentCardPage').DocumentCardPage, key: 'DocumentCard', name: 'DocumentCard', url: '#/examples/documentcard' }, { - getComponent: cb => cb(require('../components/Dropdown/DropdownPage').DropdownPage), + component: require('../components/Dropdown/DropdownPage').DropdownPage, key: 'Dropdown', name: 'Dropdown', url: '#/examples/dropdown' }, { - getComponent: cb => cb(require('../components/Facepile/FacepilePage').FacepilePage), + component: require('../components/Facepile/FacepilePage').FacepilePage, key: 'Facepile', name: 'Facepile', url: '#/examples/facepile' }, { - getComponent: cb => cb(require('../components/Icon/IconPage').IconPage), + component: require('../components/Icon/IconPage').IconPage, key: 'Icon', name: 'Icon', url: '#/examples/icon' }, { - getComponent: cb => cb(require('../components/Label/LabelPage').LabelPage), + component: require('../components/Label/LabelPage').LabelPage, key: 'Label', name: 'Label', url: '#/examples/label' }, { - getComponent: cb => cb(require('../components/Link/LinkPage').LinkPage), + component: require('../components/Link/LinkPage').LinkPage, key: 'Link', name: 'Link', url: '#/examples/link' }, { - getComponent: cb => cb(require('../components/List/ListPage').ListPage), + component: require('../components/List/ListPage').ListPage, key: 'List', name: 'List', url: '#/examples/list' }, { - getComponent: cb => cb(require('../components/MessageBar/MessageBarPage').MessageBarPage), + component: require('../components/MessageBar/MessageBarPage').MessageBarPage, key: 'MessageBar', name: 'MessageBar', url: '#/examples/messagebar' }, { - getComponent: cb => cb(require('../components/Modal/ModalPage').ModalPage), + component: require('../components/Modal/ModalPage').ModalPage, key: 'Modal', name: 'Modal', url: '#/examples/modal' }, { - getComponent: cb => cb(require('../components/Overlay/OverlayPage').OverlayPage), + component: require('../components/Overlay/OverlayPage').OverlayPage, key: 'Overlay', name: 'Overlay', url: '#/examples/overlay' }, { - getComponent: cb => cb(require('../components/OverflowSet/OverflowSetPage').OverflowSetPage), + component: require('../components/OverflowSet/OverflowSetPage').OverflowSetPage, key: 'OverflowSet', name: 'OverflowSet', url: '#/examples/overflowset' }, { - getComponent: cb => cb(require('../components/Panel/PanelPage').PanelPage), + component: require('../components/Panel/PanelPage').PanelPage, key: 'Panel', name: 'Panel', url: '#/examples/panel' }, { - getComponent: cb => cb(require('../components/pickers/PickersPage').PickersPage), + component: require('../components/pickers/PickersPage').PickersPage, key: 'Pickers', name: 'Pickers', url: '#/examples/pickers' }, { - getComponent: cb => cb(require('../components/pickers/PeoplePicker/PeoplePickerPage').PeoplePickerPage), + component: require('../components/pickers/PeoplePicker/PeoplePickerPage').PeoplePickerPage, key: 'PeoplePicker', name: 'PeoplePicker', url: '#/examples/PeoplePicker' }, { - getComponent: cb => cb(require('../components/Persona/PersonaPage').PersonaPage), + component: require('../components/Persona/PersonaPage').PersonaPage, key: 'Persona', name: 'Persona', url: '#/examples/persona' }, { - getComponent: cb => cb(require('../components/Pivot/PivotPage').PivotPage), + component: require('../components/Pivot/PivotPage').PivotPage, key: 'Pivot', name: 'Pivot', url: '#/examples/pivot' }, { - getComponent: cb => cb(require('../components/ProgressIndicator/ProgressIndicatorPage').ProgressIndicatorPage), + component: require('../components/ProgressIndicator/ProgressIndicatorPage').ProgressIndicatorPage, key: 'ProgressIndicator', name: 'ProgressIndicator', url: '#/examples/progressindicator' }, { - getComponent: cb => cb(require('../components/Rating/RatingPage').RatingPage), + component: require('../components/Rating/RatingPage').RatingPage, key: 'Rating', name: 'Rating', url: '#/examples/rating' }, { - getComponent: cb => cb(require('../components/SearchBox/SearchBoxPage').SearchBoxPage), + component: require('../components/SearchBox/SearchBoxPage').SearchBoxPage, key: 'SearchBox', name: 'SearchBox', url: '#/examples/searchbox' }, { - getComponent: cb => cb(require('../components/Spinner/SpinnerPage').SpinnerPage), + component: require('../components/Spinner/SpinnerPage').SpinnerPage, key: 'Spinner', name: 'Spinner', url: '#/examples/spinner' }, { - getComponent: cb => cb(require('../components/TeachingBubble/TeachingBubblePage').TeachingBubblePage), + component: require('../components/TeachingBubble/TeachingBubblePage').TeachingBubblePage, key: 'TeachingBubble', name: 'TeachingBubble', url: '#/examples/teachingbubble' }, { - getComponent: cb => cb(require('../components/TextField/TextFieldPage').TextFieldPage), + component: require('../components/TextField/TextFieldPage').TextFieldPage, key: 'TextField', name: 'TextField', url: '#/examples/textfield' }, { - getComponent: cb => cb(require('../components/Toggle/TogglePage').TogglePage), + component: require('../components/Toggle/TogglePage').TogglePage, key: 'Toggle', name: 'Toggle', url: '#/examples/toggle' }, { - getComponent: cb => cb(require('../components/Tooltip/TooltipPage').TooltipPage), + component: require('../components/Tooltip/TooltipPage').TooltipPage, key: 'Tooltip', name: 'Tooltip', url: '#/examples/Tooltip' @@ -232,37 +232,37 @@ export const AppDefinition: IAppDefinition = { { links: [ { - getComponent: cb => cb(require('../components/ColorPicker/ColorPickerPage').ColorPickerPage), + component: require('../components/ColorPicker/ColorPickerPage').ColorPickerPage, key: 'ColorPicker', name: 'ColorPicker', url: '#/examples/colorpicker' }, { - getComponent: cb => cb(require('../components/GroupedList/GroupedListPage').GroupedListPage), + component: require('../components/GroupedList/GroupedListPage').GroupedListPage, key: 'GroupedList', name: 'GroupedList', url: '#examples/groupedlist' }, { - getComponent: cb => cb(require('../components/Image/ImagePage').ImagePage), + component: require('../components/Image/ImagePage').ImagePage, key: 'Image', name: 'Image', url: '#/examples/image' }, { - getComponent: cb => cb(require('../components/Layer/LayerPage').LayerPage), + component: require('../components/Layer/LayerPage').LayerPage, key: 'Layer', name: 'Layer', url: '#/examples/layer' }, { - getComponent: cb => cb(require('../components/Nav/NavPage').NavPage), + component: require('../components/Nav/NavPage').NavPage, key: 'Nav', name: 'Nav', url: '#/examples/nav' }, { - getComponent: cb => cb(require('../components/Slider/SliderPage').SliderPage), + component: require('../components/Slider/SliderPage').SliderPage, key: 'Slider', name: 'Slider', url: '#/examples/slider' @@ -273,31 +273,31 @@ export const AppDefinition: IAppDefinition = { { links: [ { - getComponent: cb => cb(require('../components/FocusTrapZone/FocusTrapZonePage').FocusTrapZonePage), + component: require('../components/FocusTrapZone/FocusTrapZonePage').FocusTrapZonePage, key: 'FocusTrapZone', name: 'FocusTrapZone', url: '#examples/focustrapzone' }, { - getComponent: cb => cb(require('../components/FocusZone/FocusZonePage').FocusZonePage), + component: require('../components/FocusZone/FocusZonePage').FocusZonePage, key: 'FocusZone', name: 'FocusZone', url: '#examples/focuszone' }, { - getComponent: cb => cb(require('../components/MarqueeSelection/MarqueeSelectionPage').MarqueeSelectionPage), + component: require('../components/MarqueeSelection/MarqueeSelectionPage').MarqueeSelectionPage, key: 'MarqueeSelection', name: 'MarqueeSelection', url: '#examples/marqueeselection' }, { - getComponent: cb => cb(require('../utilities/selection/SelectionPage').SelectionPage), + component: require('../utilities/selection/SelectionPage').SelectionPage, key: 'Selection', name: 'Selection', url: '#examples/selection' }, { - getComponent: cb => cb(require('../components/Theme/ThemePage').ThemePage), + component: require('../components/Theme/ThemePage').ThemePage, key: 'Theme', name: 'Themes', url: '#examples/themes' diff --git a/packages/styling/package.json b/packages/styling/package.json index fedb3aaeb520a6..8535ea6cb64dff 100644 --- a/packages/styling/package.json +++ b/packages/styling/package.json @@ -34,7 +34,7 @@ "tslint-microsoft-contrib": "^4.0.1", "typescript": "2.2.2", "uglifyjs-webpack-plugin": "^0.4.3", - "webpack": "^2.2.1", + "webpack": "^2.4.1", "webpack-bundle-analyzer": "^2.2.1", "webpack-dev-server": "^2.4.1", "webpack-notifier": "^1.5.0", diff --git a/packages/utilities/src/rtl.ts b/packages/utilities/src/rtl.ts index 34e80638ffbd3a..05d5423a5d1cf8 100644 --- a/packages/utilities/src/rtl.ts +++ b/packages/utilities/src/rtl.ts @@ -1,5 +1,5 @@ import { KeyCodes } from './KeyCodes'; -import { getDocument } from './dom'; +import { getDocument, getWindow } from './dom'; // Default to undefined so that we initialize on first read. let _isRTL: boolean; @@ -29,13 +29,13 @@ export function getRTL(): boolean { */ export function setRTL(isRTL: boolean) { let doc = getDocument(); - if (doc) { doc.documentElement.setAttribute('dir', isRTL ? 'rtl' : 'ltr'); } + let win = getWindow(); // tslint:disable-next-line:no-string-literal - if (window['localStorage']) { + if (win && win['localStorage']) { localStorage.setItem('isRTL', isRTL ? '1' : '0'); } diff --git a/rush.json b/rush.json index c4129b25e3f78a..93519cae72fc5d 100644 --- a/rush.json +++ b/rush.json @@ -37,6 +37,11 @@ "projectFolder": "packages/example-component", "shouldPublish": false }, + { + "packageName": "ssr-tests", + "projectFolder": "apps/ssr-tests", + "shouldPublish": false + }, { "packageName": "todo-app", "projectFolder": "apps/todo-app",