From 0f527b37dce0ebbadaa5f0b26560f2338bae992d Mon Sep 17 00:00:00 2001 From: Anthony Gubler Date: Mon, 26 Jun 2017 09:56:38 +0100 Subject: [PATCH 1/6] Changes for next widget-core release --- src/calendar/Calendar.ts | 26 +++++------ src/combobox/ComboBox.ts | 30 +++++-------- src/select/Select.ts | 77 +++++++++++++++------------------ src/select/tests/unit/Select.ts | 2 +- src/timepicker/TimePicker.ts | 19 ++++---- 5 files changed, 66 insertions(+), 88 deletions(-) diff --git a/src/calendar/Calendar.ts b/src/calendar/Calendar.ts index 06659df8f1..97c5e6129a 100644 --- a/src/calendar/Calendar.ts +++ b/src/calendar/Calendar.ts @@ -1,10 +1,10 @@ -import { WidgetBase, onPropertiesChanged, diffProperty, DiffType } from '@dojo/widget-core/WidgetBase'; +import { WidgetBase, diffProperty } from '@dojo/widget-core/WidgetBase'; import { ThemeableMixin, ThemeableProperties, theme } from '@dojo/widget-core/mixins/Themeable'; import WidgetRegistry from '@dojo/widget-core/WidgetRegistry'; import { v, w } from '@dojo/widget-core/d'; -import { DNode, PropertiesChangeEvent, Constructor } from '@dojo/widget-core/interfaces'; +import { reference } from '@dojo/widget-core/diff'; +import { DNode, Constructor } from '@dojo/widget-core/interfaces'; import uuid from '@dojo/core/uuid'; -import { includes } from '@dojo/shim/array'; import { Keys } from '../common/util'; import MonthPicker, { CalendarMessages } from './MonthPicker'; import CalendarCell from './CalendarCell'; @@ -41,7 +41,7 @@ export interface CalendarProperties extends ThemeableProperties { onMonthChange?(month: number): void; onYearChange?(year: number): void; onDateSelect?(date: Date): void; -}; +} export const DEFAULT_MONTHS = [ {short: 'Jan', long: 'January'}, @@ -78,7 +78,6 @@ export const DEFAULT_LABELS: CalendarMessages = { export const CalendarBase = ThemeableMixin(WidgetBase); @theme(css) -@diffProperty('customDateCell', DiffType.REFERENCE) export default class Calendar extends CalendarBase { private _callDateFocus = false; private _defaultDate = new Date(); @@ -95,17 +94,12 @@ export default class Calendar extends CalendarBase { this.registries.add(this._registry); } - @onPropertiesChanged() - protected onPropertiesChanged(evt: PropertiesChangeEvent) { - const { customDateCell = CalendarCell } = this.properties; - - // update custom option registry - if ( includes(evt.changedPropertyKeys, 'customDateCell')) { - const registry = this._createRegistry(customDateCell); - - this.registries.replace(this._registry, registry); - this._registry = registry; - } + @diffProperty('customDateCell', reference) + protected onPropertiesChanged(previousProperties: any, newProperties: any) { + const { customDateCell = CalendarCell } = newProperties; + const registry = this._createRegistry(customDateCell); + this.registries.replace(this._registry, registry); + this._registry = registry; } private _createRegistry(customDateCell: any) { diff --git a/src/combobox/ComboBox.ts b/src/combobox/ComboBox.ts index eeb0af66b1..8369c74b35 100644 --- a/src/combobox/ComboBox.ts +++ b/src/combobox/ComboBox.ts @@ -1,9 +1,9 @@ import uuid from '@dojo/core/uuid'; -import { includes } from '@dojo/shim/array'; import { v, w } from '@dojo/widget-core/d'; -import { DNode, WNode, PropertiesChangeEvent } from '@dojo/widget-core/interfaces'; +import { DNode, WNode } from '@dojo/widget-core/interfaces'; import { ThemeableMixin, ThemeableProperties, theme } from '@dojo/widget-core/mixins/Themeable'; -import { WidgetBase, onPropertiesChanged, diffProperty, DiffType } from '@dojo/widget-core/WidgetBase'; +import { WidgetBase, diffProperty } from '@dojo/widget-core/WidgetBase'; +import { reference } from '@dojo/widget-core/diff'; import WidgetRegistry from '@dojo/widget-core/WidgetRegistry'; import ResultItem from './ResultItem'; import ResultMenu from './ResultMenu'; @@ -63,20 +63,18 @@ export interface ComboBoxProperties extends ThemeableProperties { required?: boolean; results?: any[]; value?: string; -}; +} // Enum used when traversing items using arrow keys export const enum Operation { increase = 1, decrease = -1 -}; +} export const ComboBoxBase = ThemeableMixin(WidgetBase); @theme(css) @theme(iconCss) -@diffProperty('customResultItem', DiffType.REFERENCE) -@diffProperty('customResultMenu', DiffType.REFERENCE) export default class ComboBox extends ComboBoxBase { private _activeIndex: number | undefined; private _focused: boolean; @@ -311,21 +309,17 @@ export default class ComboBox extends ComboBoxBase { } } - @onPropertiesChanged() - protected onPropertiesChanged(evt: PropertiesChangeEvent) { + @diffProperty('customResultItem', reference) + @diffProperty('customResultMenu', reference) + protected onPropertiesChanged(previousProperties: any, newProperties: any) { const { customResultItem = ResultItem, customResultMenu = ResultMenu - } = this.properties; + } = newProperties; - if ( - includes(evt.changedPropertyKeys, 'customResultItem') || - includes(evt.changedPropertyKeys, 'customResultMenu')) { - const registry = this._createRegistry(customResultItem, customResultMenu); - - this.registries.replace(this._registry, registry); - this._registry = registry; - } + const registry = this._createRegistry(customResultItem, customResultMenu); + this.registries.replace(this._registry, registry); + this._registry = registry; } protected renderMenu(results: any[]): WNode | null { diff --git a/src/select/Select.ts b/src/select/Select.ts index 977122b253..9c9e7c2b75 100644 --- a/src/select/Select.ts +++ b/src/select/Select.ts @@ -1,11 +1,12 @@ -import { WidgetBase, onPropertiesChanged, diffProperty, DiffType } from '@dojo/widget-core/WidgetBase'; -import { DNode, PropertiesChangeEvent } from '@dojo/widget-core/interfaces'; +import { WidgetBase, diffProperty } from '@dojo/widget-core/WidgetBase'; +import { DNode } from '@dojo/widget-core/interfaces'; import { ThemeableMixin, ThemeableProperties, theme } from '@dojo/widget-core/mixins/Themeable'; import WidgetRegistry from '@dojo/widget-core/WidgetRegistry'; import { v, w } from '@dojo/widget-core/d'; +import { reference, auto } from '@dojo/widget-core/diff'; import uuid from '@dojo/core/uuid'; import { assign } from '@dojo/core/lang'; -import { find, includes } from '@dojo/shim/array'; +import { find } from '@dojo/shim/array'; import { Keys } from '../common/util'; import Label, { LabelOptions, parseLabelClasses } from '../label/Label'; import SelectOption, { OptionData } from './SelectOption'; @@ -61,13 +62,13 @@ export const SelectBase = ThemeableMixin(WidgetBase); @theme(css) @theme(iconCss) -@diffProperty('customOption', DiffType.REFERENCE) export default class Select extends SelectBase { private _focusedIndex = 0; private _ignoreBlur = false; private _open = false; private _selectId = uuid(); private _registry: WidgetRegistry; + private _options: OptionData[] = []; private _onBlur (event: FocusEvent) { this.properties.onBlur && this.properties.onBlur(event); } private _onClick (event: MouseEvent) { this.properties.onClick && this.properties.onClick(event); } @@ -92,11 +93,10 @@ export default class Select extends SelectBase { // native select events private _onNativeChange (event: Event) { const { - options = [], onChange } = this.properties; const value = ( event.target).value; - const option = find(options, (option: OptionData) => option.value === value); + const option = find(this._options, (option: OptionData) => option.value === value); onChange && onChange(option); } @@ -132,14 +132,13 @@ export default class Select extends SelectBase { private _onOptionClick(event: MouseEvent, index: number) { const { - options = [], onChange, onClick } = this.properties; onClick && onClick(event); - const option = options[index]; + const option = this._options[index]; // if the option exists and isn't disabled, focus it and fire onChange if (option && !option.disabled) { @@ -156,7 +155,6 @@ export default class Select extends SelectBase { this.properties.onKeyDown && this.properties.onKeyDown(event); const { - options = [], multiple, onChange } = this.properties; @@ -164,19 +162,19 @@ export default class Select extends SelectBase { switch (event.which) { case Keys.Enter: - if (options[_focusedIndex].disabled) { + if (this._options[_focusedIndex].disabled) { event.preventDefault(); } else { - onChange && onChange(options[_focusedIndex]); + onChange && onChange(this._options[_focusedIndex]); } break; case Keys.Space: - if (options[_focusedIndex].disabled) { + if (this._options[_focusedIndex].disabled) { event.preventDefault(); } else { - onChange && onChange(options[_focusedIndex]); + onChange && onChange(this._options[_focusedIndex]); } break; case Keys.Escape: @@ -185,7 +183,7 @@ export default class Select extends SelectBase { case Keys.Down: event.preventDefault(); if (this._open || multiple) { - this._focusedIndex = (_focusedIndex + 1) % options.length; + this._focusedIndex = (_focusedIndex + 1) % this._options.length; } else { this._openSelect(); } @@ -193,7 +191,7 @@ export default class Select extends SelectBase { break; case Keys.Up: event.preventDefault(); - this._focusedIndex = (_focusedIndex - 1 + options.length) % options.length; + this._focusedIndex = (_focusedIndex - 1 + this._options.length) % this._options.length; this.invalidate(); break; case Keys.Home: @@ -201,7 +199,7 @@ export default class Select extends SelectBase { this.invalidate(); break; case Keys.End: - this._focusedIndex = options.length - 1; + this._focusedIndex = this._options.length - 1; this.invalidate(); break; } @@ -210,12 +208,11 @@ export default class Select extends SelectBase { private _renderCustomOptions(): DNode[] { const { multiple, - options = [], value, theme } = this.properties; - const optionNodes = options.map((option, i) => w('select-option', { + const optionNodes = this._options.map((option, i) => w('select-option', { focused: this._focusedIndex === i, index: i, key: i + '', @@ -231,27 +228,26 @@ export default class Select extends SelectBase { return optionNodes; } - @onPropertiesChanged() - protected onPropertiesChanged(evt: PropertiesChangeEvent) { + @diffProperty('customOption', reference) + protected onCustomOptionChange(previousProperties: any, newProperties: any) { const { - customOption = SelectOption, - options = [] - } = this.properties; + customOption = SelectOption + } = newProperties; - // update custom option registry - if ( includes(evt.changedPropertyKeys, 'customOption')) { - const registry = this._createRegistry(customOption); + const registry = this._createRegistry(customOption); + this.registries.replace(this._registry, registry); + this._registry = registry; + } - this.registries.replace(this._registry, registry); - this._registry = registry; - } + @diffProperty('options', auto) + protected onOptionsChange(previousProperties: { options: OptionData[] }, newProperties: { options: OptionData[] }) { + const { + options = [] + } = newProperties; - // add ids to options for use with aria-activedescendant - if (includes(evt.changedPropertyKeys, 'options')) { - options.forEach((option) => { - option.id = option.id || uuid(); - }); - } + this._options = options.map((option) => { + return { id: uuid(), ...option }; + }); } renderNativeSelect(): DNode { @@ -261,14 +257,13 @@ export default class Select extends SelectBase { invalid, multiple, name, - options = [], readOnly, required, value } = this.properties; /* create option nodes */ - const optionNodes = options.map(option => v('option', { + const optionNodes = this._options.map(option => v('option', { value: option.value, innerHTML: option.label, disabled: option.disabled, @@ -309,7 +304,6 @@ export default class Select extends SelectBase { describedBy, disabled, invalid, - options = [], readOnly, required } = this.properties; @@ -322,7 +316,7 @@ export default class Select extends SelectBase { 'aria-describedby': describedBy, 'aria-invalid': invalid ? 'true' : null, 'aria-multiselectable': 'true', - 'aria-activedescendant': options.length > 0 ? options[_focusedIndex].id : null, + 'aria-activedescendant': this._options.length > 0 ? this._options[_focusedIndex].id : null, 'aria-readonly': readOnly ? 'true' : null, 'aria-required': required ? 'true' : null, tabIndex: 0, @@ -338,7 +332,6 @@ export default class Select extends SelectBase { describedBy, disabled, invalid, - options = [], readOnly, required, value @@ -350,7 +343,7 @@ export default class Select extends SelectBase { _selectId } = this; - const selectedOption = find(options, (option: OptionData) => option.value === value) || options[0]; + const selectedOption = find(this._options, (option: OptionData) => option.value === value) || this._options[0]; // create dropdown trigger and select box return v('div', { @@ -363,7 +356,7 @@ export default class Select extends SelectBase { 'aria-owns': _selectId, 'aria-expanded': _open + '', 'aria-haspopup': 'listbox', - 'aria-activedescendant': options.length > 0 ? options[_focusedIndex].id : null, + 'aria-activedescendant': this._options.length > 0 ? this._options[_focusedIndex].id : null, value, onblur: this._onTriggerBlur, onclick: this._onTriggerClick, diff --git a/src/select/tests/unit/Select.ts b/src/select/tests/unit/Select.ts index 005f9b63a3..6cfde72d8a 100644 --- a/src/select/tests/unit/Select.ts +++ b/src/select/tests/unit/Select.ts @@ -455,7 +455,7 @@ registerSuite({ ( select)._onListboxKeyDown(event(keys.space)); const vnode = select.__render__(); assert.strictEqual(selectedOption, 'two', 'Down arrow navigates to second option'); - assert.strictEqual(vnode.children![0].children![0].properties!['aria-activedescendant'], testOptions[1].id, 'Set activedescendant to second option id'); + assert.isDefined(vnode.children![0].children![0].properties!['aria-activedescendant'], 'Set activedescendant to second option id'); ( select)._onListboxKeyDown(event(keys.up)); ( select)._onListboxKeyDown(event(keys.enter)); diff --git a/src/timepicker/TimePicker.ts b/src/timepicker/TimePicker.ts index b852edf4be..35416d5455 100644 --- a/src/timepicker/TimePicker.ts +++ b/src/timepicker/TimePicker.ts @@ -1,9 +1,9 @@ -import { includes } from '@dojo/shim/array'; import { padStart } from '@dojo/shim/string'; import { v, w } from '@dojo/widget-core/d'; -import { DNode, PropertiesChangeEvent } from '@dojo/widget-core/interfaces'; +import { DNode } from '@dojo/widget-core/interfaces'; import ThemeableMixin, { theme, ThemeableProperties } from '@dojo/widget-core/mixins/Themeable'; -import WidgetBase, { onPropertiesChanged } from '@dojo/widget-core/WidgetBase'; +import { diffProperty, WidgetBase } from '@dojo/widget-core/WidgetBase'; +import { auto } from '@dojo/widget-core/diff'; import * as css from './styles/timePicker.m.css'; import ComboBox from '../combobox/ComboBox'; import Label, { LabelOptions, parseLabelClasses } from '../label/Label'; @@ -216,14 +216,11 @@ export class TimePicker extends TimePickerBase { return this.options; } - @onPropertiesChanged() - protected onPropertiesChanged(event: PropertiesChangeEvent) { - if ( - includes(event.changedPropertyKeys, 'start') || - includes(event.changedPropertyKeys, 'end') || - includes(event.changedPropertyKeys, 'step')) { - this.options = null; - } + @diffProperty('start', auto) + @diffProperty('end', auto) + @diffProperty('step', auto) + protected onPropertiesChanged() { + this.options = null; } protected renderNativeInput() { From 96a3249a86eb5a66941143b7b42888aaa21d6f62 Mon Sep 17 00:00:00 2001 From: Anthony Gubler Date: Mon, 26 Jun 2017 15:20:51 +0100 Subject: [PATCH 2/6] remove StatefulMixin from examples --- src/button/example/index.ts | 10 +-- src/calendar/example/index.ts | 28 +++++--- src/checkbox/example/index.ts | 16 +++-- src/combobox/example/index.ts | 70 ++++++++++++-------- src/common/example/index.html | 4 +- src/common/example/index.ts | 5 +- src/dialog/example/index.ts | 36 +++++++---- src/label/example/index.ts | 5 +- src/radio/example/index.ts | 18 +++--- src/select/example/index.ts | 19 +++--- src/slidepane/example/index.ts | 24 ++++--- src/slider/example/index.ts | 25 ++++---- src/splitpane/example/index.ts | 10 ++- src/tabpane/example/index.ts | 24 ++++++- src/textarea/example/index.ts | 21 +++--- src/textinput/example/index.ts | 33 ++++++---- src/timepicker/example/index.ts | 110 +++++++++++++++++++------------- src/titlepane/example/index.ts | 27 ++++---- 18 files changed, 292 insertions(+), 193 deletions(-) diff --git a/src/button/example/index.ts b/src/button/example/index.ts index d0ac0facbf..10d28e4865 100644 --- a/src/button/example/index.ts +++ b/src/button/example/index.ts @@ -1,14 +1,13 @@ import { WidgetBase } from '@dojo/widget-core/WidgetBase'; import { WidgetProperties, TypedTargetEvent } from '@dojo/widget-core/interfaces'; -import { StatefulMixin } from '@dojo/widget-core/mixins/Stateful'; import { ProjectorMixin } from '@dojo/widget-core/mixins/Projector'; import { w, v } from '@dojo/widget-core/d'; import Button from '../../button/Button'; import dojoTheme from '../../themes/dojo/theme'; -export const AppBase = StatefulMixin(WidgetBase); -export class App extends AppBase { +export class App extends WidgetBase { private _theme: {}; + private _buttonPressed = false; themeChange(event: TypedTargetEvent) { const checked = event.target.checked; @@ -17,7 +16,8 @@ export class App extends AppBase { } toggleButton() { - this.setState({ buttonPressed: !this.state.buttonPressed }); + this._buttonPressed = !this._buttonPressed; + this.invalidate(); } render() { @@ -52,7 +52,7 @@ export class App extends AppBase { w(Button, { key: 'b3', theme: this._theme, - pressed: this.state.buttonPressed, + pressed: this._buttonPressed, onClick: this.toggleButton }, [ 'Button state' ]) ]) diff --git a/src/calendar/example/index.ts b/src/calendar/example/index.ts index 2adbef18cc..c1d01a6966 100644 --- a/src/calendar/example/index.ts +++ b/src/calendar/example/index.ts @@ -1,15 +1,16 @@ import { WidgetBase } from '@dojo/widget-core/WidgetBase'; import { WidgetProperties } from '@dojo/widget-core/interfaces'; -import { StatefulMixin } from '@dojo/widget-core/mixins/Stateful'; import { ProjectorMixin } from '@dojo/widget-core/mixins/Projector'; import { v, w } from '@dojo/widget-core/d'; import Calendar from '../../calendar/Calendar'; import Checkbox from '../../checkbox/Checkbox'; import dojoTheme from '../../themes/dojo/theme'; -const AppBase = StatefulMixin(WidgetBase); -export class App extends AppBase { +export class App extends WidgetBase { private _theme: {}; + private _month: number; + private _year: number; + private _selectedDate: Date; themeChange(event: Event) { const checked = ( event.target).checked; @@ -27,17 +28,24 @@ export class App extends AppBase { onChange: this.themeChange }), w(Calendar, { - month: this.state.month, - selectedDate: this.state.selectedDate, + month: this._month, + selectedDate: this._selectedDate, theme: this._theme, - year: this.state.year, - onMonthChange: (month: number) => { this.setState({ 'month': month }); }, - onYearChange: (year: number) => { this.setState({ 'year': year }); }, + year: this._year, + onMonthChange: (month: number) => { + this._month = month; + this.invalidate(); + }, + onYearChange: (year: number) => { + this._year = year; + this.invalidate(); + }, onDateSelect: (date: Date) => { - this.setState({ 'selectedDate': date }); + this._selectedDate = date; + this.invalidate(); } }), - this.state.selectedDate ? v('p', [ `Selected Date: ${this.state.selectedDate.toDateString()}` ]) : null + this._selectedDate ? v('p', [ `Selected Date: ${this._selectedDate.toDateString()}` ]) : null ]); } } diff --git a/src/checkbox/example/index.ts b/src/checkbox/example/index.ts index c081ae0a7b..d8dc66cc83 100644 --- a/src/checkbox/example/index.ts +++ b/src/checkbox/example/index.ts @@ -1,14 +1,19 @@ import { WidgetBase } from '@dojo/widget-core/WidgetBase'; import { WidgetProperties, TypedTargetEvent } from '@dojo/widget-core/interfaces'; import { ProjectorMixin } from '@dojo/widget-core/mixins/Projector'; -import { StatefulMixin } from '@dojo/widget-core/mixins/Stateful'; import { v, w } from '@dojo/widget-core/d'; import Checkbox, { Mode } from '../../checkbox/Checkbox'; import dojoTheme from '../../themes/dojo/theme'; -export const AppBase = StatefulMixin(WidgetBase); -export class App extends AppBase { +export class App extends WidgetBase { private _theme: {}; + private _checkboxStates: { [key: string]: boolean } = { + c1: true, + c2: false, + c3: false, + c4: false, + c5: true + }; themeChange(event: TypedTargetEvent) { const checked = event.target.checked; @@ -19,7 +24,8 @@ export class App extends AppBase { onChange(event: TypedTargetEvent) { const value = event.target.value; const checked = event.target.checked; - this.setState({ [value]: checked }); + this._checkboxStates[value] = checked; + this.invalidate(); } render() { @@ -29,7 +35,7 @@ export class App extends AppBase { c3 = false, c4 = false, c5 = true - } = this.state; + } = this._checkboxStates; return v('div', [ v('h2', { diff --git a/src/combobox/example/index.ts b/src/combobox/example/index.ts index 382e7ed9fb..f447591bde 100644 --- a/src/combobox/example/index.ts +++ b/src/combobox/example/index.ts @@ -1,6 +1,5 @@ import { DNode, WNode } from '@dojo/widget-core/interfaces'; import { ProjectorMixin } from '@dojo/widget-core/mixins/Projector'; -import { StatefulMixin } from '@dojo/widget-core/mixins/Stateful'; import { v, w } from '@dojo/widget-core/d'; import { WidgetBase } from '@dojo/widget-core/WidgetBase'; import { WidgetProperties } from '@dojo/widget-core/interfaces'; @@ -114,8 +113,17 @@ class CustomResultMenu extends ResultMenu { } } -export class App extends StatefulMixin(WidgetBase) { +export class App extends WidgetBase { private _theme: {}; + private _results: any[]; + private _valueOne: string; + private _valueTwo: string; + private _valueThree: string; + private _valueFour: string; + private _valueFive: string; + private _valueEight: string; + private _valueNine: string; + private _invalid: boolean; themeChange(event: Event) { const checked = ( event.target).checked; @@ -129,7 +137,8 @@ export class App extends StatefulMixin(WidgetBase) { return Boolean(match && match.length > 0); }); - this.setState({ results: results.sort((a, b) => a.value < b.value ? -1 : 1) }); + this._results = results.sort((a, b) => a.value < b.value ? -1 : 1); + this.invalidate(); } render(): DNode { @@ -147,12 +156,13 @@ export class App extends StatefulMixin(WidgetBase) { key: '2', clearable: true, onChange: (value: string) => { - this.setState({ 'value2': value }); + this._valueTwo = value; + this.invalidate(); }, getResultLabel: (result: any) => result.value, onRequestResults: this.onRequestResults, - results: this.state.results, - value: this.state.value2, + results: this._results, + value: this._valueTwo, inputProperties: { placeholder: 'Enter a value' }, @@ -163,12 +173,13 @@ export class App extends StatefulMixin(WidgetBase) { key: '1', openOnFocus: true, onChange: (value: string) => { - this.setState({ 'value1': value }); + this._valueOne = value; + this.invalidate(); }, getResultLabel: (result: any) => result.value, onRequestResults: this.onRequestResults, - results: this.state.results, - value: this.state.value1, + results: this._results, + value: this._valueOne, inputProperties: { placeholder: 'Enter a value' }, @@ -179,13 +190,14 @@ export class App extends StatefulMixin(WidgetBase) { key: '3', openOnFocus: true, onChange: (value: string) => { - this.setState({ 'value3': value }); + this._valueThree = value; + this.invalidate(); }, getResultLabel: (result: any) => result.value, onRequestResults: this.onRequestResults, customResultItem: CustomResultItem, - results: this.state.results, - value: this.state.value3, + results: this._results, + value: this._valueThree, inputProperties: { placeholder: 'Enter a value' }, @@ -195,12 +207,13 @@ export class App extends StatefulMixin(WidgetBase) { w(ComboBox, { key: '4', onChange: (value: string) => { - this.setState({ 'value4': value }); + this._valueFour = value; + this.invalidate(); }, getResultLabel: (result: any) => result.value, onRequestResults: this.onRequestResults, - results: this.state.results, - value: this.state.value4, + results: this._results, + value: this._valueFour, customResultMenu: CustomResultMenu, inputProperties: { placeholder: 'Enter a value' @@ -211,12 +224,13 @@ export class App extends StatefulMixin(WidgetBase) { w(ComboBox, { key: '5', onChange: (value: string) => { - this.setState({ 'value5': value }); + this._valueFive = value; + this.invalidate(); }, getResultLabel: (result: any) => result.value, onRequestResults: this.onRequestResults, - results: this.state.results, - value: this.state.value5, + results: this._results, + value: this._valueFive, isResultDisabled: (result: any) => result.value.length > 9, inputProperties: { placeholder: 'Enter a value' @@ -245,12 +259,13 @@ export class App extends StatefulMixin(WidgetBase) { w(ComboBox, { key: '8', onChange: (value: string) => { - this.setState({ 'value8': value }); + this._valueEight = value; + this.invalidate(); }, getResultLabel: (result: any) => result.value, onRequestResults: this.onRequestResults, - results: this.state.results, - value: this.state.value8, + results: this._results, + value: this._valueEight, label: 'Enter a value', theme: this._theme }), @@ -259,16 +274,15 @@ export class App extends StatefulMixin(WidgetBase) { key: '9', required: true, onChange: (value: string) => { - this.setState({ - 'value9': value, - invalid: value.trim().length === 0 - }); + this._valueNine = value; + this._invalid = value.trim().length === 0; + this.invalidate(); }, getResultLabel: (result: any) => result.value, onRequestResults: this.onRequestResults, - results: this.state.results, - value: this.state.value9, - invalid: this.state.invalid, + results: this._results, + value: this._valueNine, + invalid: this._invalid, inputProperties: { placeholder: 'Enter a value' }, diff --git a/src/common/example/index.html b/src/common/example/index.html index aae3625201..4a03bb7dac 100644 --- a/src/common/example/index.html +++ b/src/common/example/index.html @@ -49,12 +49,10 @@ } } + require([ 'src/common/example/index' ], function () {}); if (module) { require([ 'src/' + module + '/example/index' ], function () {}); } - else { - require([ 'src/common/example/index' ], function () {}); - } })(); diff --git a/src/common/example/index.ts b/src/common/example/index.ts index d8069eed1f..bcfc5f5c5a 100644 --- a/src/common/example/index.ts +++ b/src/common/example/index.ts @@ -1,12 +1,9 @@ import { WidgetBase } from '@dojo/widget-core/WidgetBase'; import { WidgetProperties } from '@dojo/widget-core/interfaces'; -import { StatefulMixin } from '@dojo/widget-core/mixins/Stateful'; import { ProjectorMixin } from '@dojo/widget-core/mixins/Projector'; import Select from '../../select/Select'; import { v, w } from '@dojo/widget-core/d'; -export const AppBase = StatefulMixin(WidgetBase); - const modules = [ 'button', 'calendar', @@ -26,7 +23,7 @@ const modules = [ 'titlepane' ]; -export class App extends AppBase { +export class App extends WidgetBase { onModuleChange(event: any) { const module = event.value; window.location.search = `?module=${module}`; diff --git a/src/dialog/example/index.ts b/src/dialog/example/index.ts index 929ff7061d..1362aa215b 100644 --- a/src/dialog/example/index.ts +++ b/src/dialog/example/index.ts @@ -1,14 +1,17 @@ import { DNode } from '@dojo/widget-core/interfaces'; import { WidgetBase } from '@dojo/widget-core/WidgetBase'; import { WidgetProperties } from '@dojo/widget-core/interfaces'; -import { StatefulMixin } from '@dojo/widget-core/mixins/Stateful'; import { ProjectorMixin } from '@dojo/widget-core/mixins/Projector'; import { v, w } from '@dojo/widget-core/d'; import Dialog from '../../dialog/Dialog'; import dojoTheme from '../../themes/dojo/theme'; -export class App extends StatefulMixin(WidgetBase) { +export class App extends WidgetBase { private _theme: {}; + private _modal = false; + private _underlay = false; + private _closeable = false; + private _open = false; themeChange(event: Event) { const checked = ( event.target).checked; @@ -17,19 +20,23 @@ export class App extends StatefulMixin(WidgetBase) { } openDialog() { - this.setState({ open: true }); + this._open = true; + this.invalidate(); } - toggleModal(event: Event) { - this.setState({ modal: ( event.target).checked }); + toggleModal(event: any) { + this._modal = event.target.checked; + this.invalidate(); } - toggleUnderlay(event: Event) { - this.setState({ underlay: ( event.target).checked }); + toggleUnderlay(event: any) { + this._underlay = event.target.checked; + this.invalidate(); } - toggleCloseable(event: Event) { - this.setState({ closeable: ( event.target).checked }); + toggleCloseable(event: any) { + this._closeable = event.target.checked; + this.invalidate(); } render(): DNode { @@ -37,12 +44,13 @@ export class App extends StatefulMixin(WidgetBase) { w(Dialog, { key: 'dialog', title: 'Dialog', - open: this.state.open, - modal: this.state.modal, - underlay: this.state.underlay, - closeable: this.state.closeable, + open: this._open, + modal: this._modal, + underlay: this._underlay, + closeable: this._closeable, onRequestClose: () => { - this.setState({ open: false }); + this._open = false; + this.invalidate(); }, theme: this._theme }, [ diff --git a/src/label/example/index.ts b/src/label/example/index.ts index e64f5b88cb..ccd7f80607 100644 --- a/src/label/example/index.ts +++ b/src/label/example/index.ts @@ -1,13 +1,10 @@ import { WidgetBase } from '@dojo/widget-core/WidgetBase'; import { WidgetProperties } from '@dojo/widget-core/interfaces'; -import { StatefulMixin } from '@dojo/widget-core/mixins/Stateful'; import { ProjectorMixin } from '@dojo/widget-core/mixins/Projector'; import { v, w } from '@dojo/widget-core/d'; import Label from '../../label/Label'; -const AppBase = StatefulMixin(WidgetBase); - -export class App extends AppBase { +export class App extends WidgetBase { render() { return v('div', [ v('h1', {}, ['Label Examples']), diff --git a/src/radio/example/index.ts b/src/radio/example/index.ts index ddfe17fdb5..06019d63c2 100644 --- a/src/radio/example/index.ts +++ b/src/radio/example/index.ts @@ -1,14 +1,13 @@ import { WidgetBase } from '@dojo/widget-core/WidgetBase'; import { WidgetProperties, TypedTargetEvent } from '@dojo/widget-core/interfaces'; import { ProjectorMixin } from '@dojo/widget-core/mixins/Projector'; -import { StatefulMixin } from '@dojo/widget-core/mixins/Stateful'; import { v, w } from '@dojo/widget-core/d'; import Radio from '../../radio/Radio'; import dojoTheme from '../../themes/dojo/theme'; -export const AppBase = StatefulMixin(WidgetBase); -export class App extends AppBase { +export class App extends WidgetBase { private _theme: {}; + private _inputValue: string; themeChange(event: TypedTargetEvent) { const checked = event.target.checked; @@ -18,13 +17,14 @@ export class App extends AppBase { onChange(event: TypedTargetEvent) { const value = event.target.value; - this.setState({ inputValue: value }); + this._inputValue = value; + this.invalidate(); } render() { const { - inputValue = 'first' - } = this.state; + _inputValue = 'first' + } = this; return v('div', [ v('h2', { @@ -41,7 +41,7 @@ export class App extends AppBase { v('legend', {}, ['Set of radio buttons with first option selected']), w(Radio, { key: 'r1', - checked: inputValue === 'first', + checked: this._inputValue === 'first', value: 'first', label: 'First option', name: 'sample-radios', @@ -50,7 +50,7 @@ export class App extends AppBase { }), w(Radio, { key: 'r2', - checked: inputValue === 'second', + checked: this._inputValue === 'second', value: 'second', label: 'Second option', name: 'sample-radios', @@ -59,7 +59,7 @@ export class App extends AppBase { }), w(Radio, { key: 'r3', - checked: inputValue === 'third', + checked: this._inputValue === 'third', value: 'third', label: 'Third option', name: 'sample-radios', diff --git a/src/select/example/index.ts b/src/select/example/index.ts index de4c174edd..bd9a909783 100644 --- a/src/select/example/index.ts +++ b/src/select/example/index.ts @@ -1,6 +1,5 @@ import { WidgetBase } from '@dojo/widget-core/WidgetBase'; import { WidgetProperties } from '@dojo/widget-core/interfaces'; -import { StatefulMixin } from '@dojo/widget-core/mixins/Stateful'; import { ProjectorMixin } from '@dojo/widget-core/mixins/Projector'; import { v, w } from '@dojo/widget-core/d'; import Select from '../Select'; @@ -18,10 +17,10 @@ class CustomOption extends SelectOption { } } -export const AppBase = StatefulMixin(WidgetBase); - -export class App extends AppBase { +export class App extends WidgetBase { private _theme: {}; + private _value1: string; + private _value2: string; themeChange(event: Event) { const checked = ( event.target).checked; @@ -108,14 +107,15 @@ export class App extends AppBase { label: 'Try changing me', options: this._selectOptions, useNativeElement: true, - value: this.state.value1, + value: this._value1, theme: this._theme, onChange: (option: OptionData) => { - this.setState({ value1: option.value }); + this._value1 = option.value; + this.invalidate(); } }), v('p', { - innerHTML: 'Result value: ' + this.state.value1 + innerHTML: 'Result value: ' + this._value1 }), v('h2', {}, [ 'Custom Select Box, single select:' ]), w(Select, { @@ -123,10 +123,11 @@ export class App extends AppBase { customOption: CustomOption, label: 'Custom box!', options: this._selectOptions, - value: this.state.value2, + value: this._value2, theme: this._theme, onChange: (option: OptionData) => { - this.setState({ value2: option.value }); + this._value2 = option.value; + this.invalidate(); } }), v('h2', {}, [ 'Native multiselect widget' ]), diff --git a/src/slidepane/example/index.ts b/src/slidepane/example/index.ts index 5cc3512aad..b4f9becc10 100644 --- a/src/slidepane/example/index.ts +++ b/src/slidepane/example/index.ts @@ -1,14 +1,16 @@ import { DNode } from '@dojo/widget-core/interfaces'; import { ProjectorMixin } from '@dojo/widget-core/mixins/Projector'; -import { StatefulMixin } from '@dojo/widget-core/mixins/Stateful'; import { v, w } from '@dojo/widget-core/d'; import { WidgetBase } from '@dojo/widget-core/WidgetBase'; import { WidgetProperties } from '@dojo/widget-core/interfaces'; import SlidePane, { Align } from '../../slidepane/SlidePane'; import dojoTheme from '../../themes/dojo/theme'; -export class App extends StatefulMixin(WidgetBase) { +export class App extends WidgetBase { private _theme: {}; + private _open = false; + private _underlay = false; + private _align: Align = Align.left; themeChange(event: Event) { const checked = ( event.target).checked; @@ -17,26 +19,30 @@ export class App extends StatefulMixin(WidgetBase) { } openSlidePane() { - this.setState({ open: true }); + this._open = true; + this.invalidate(); } toggleUnderlay(event: Event) { - this.setState({ underlay: ( event.target).checked }); + this._underlay = ( event.target).checked; + this.invalidate(); } toggleAlign(event: Event) { - this.setState({ align: ( event.target).checked ? Align.right : Align.left }); + this._align = ( event.target).checked ? Align.right : Align.left; + this.invalidate(); } render(): DNode { return v('div', [ w(SlidePane, { key: 'pane', - open: this.state.open, - underlay: this.state.underlay, - align: this.state.align, + open: this._open, + underlay: this._underlay, + align: this._align, onRequestClose: () => { - this.setState({ open: false }); + this._open = false; + this.invalidate(); }, theme: this._theme }, [ diff --git a/src/slider/example/index.ts b/src/slider/example/index.ts index b0b01781ce..7b009877e7 100644 --- a/src/slider/example/index.ts +++ b/src/slider/example/index.ts @@ -1,14 +1,15 @@ import { WidgetBase } from '@dojo/widget-core/WidgetBase'; import { WidgetProperties, TypedTargetEvent } from '@dojo/widget-core/interfaces'; import { ProjectorMixin } from '@dojo/widget-core/mixins/Projector'; -import { StatefulMixin } from '@dojo/widget-core/mixins/Stateful'; import { v, w } from '@dojo/widget-core/d'; import Slider from '../../slider/Slider'; import dojoTheme from '../../themes/dojo/theme'; -export const AppBase = StatefulMixin(WidgetBase); -export class App extends AppBase { +export class App extends WidgetBase { private _theme: {}; + private _tribbleValue: number; + private _verticalValue: number; + private _verticalInvalid: boolean; themeChange(event: TypedTargetEvent) { const checked = event.target.checked; @@ -18,23 +19,23 @@ export class App extends AppBase { onTribbleInput(event: TypedTargetEvent) { const value = event.target.value; - this.setState({ tribbleValue: parseFloat(value) }); + this._tribbleValue = parseFloat(value); + this.invalidate(); } onVerticalInput(event: TypedTargetEvent) { const value = parseFloat(event.target.value); - this.setState({ - verticalValue: value, - verticalInvalid: value > 50 ? true : false - }); + this._verticalValue = value; + this._verticalInvalid = value > 50; + this.invalidate(); } render() { const { - tribbleValue = 50, - verticalValue = 0, - verticalInvalid = false - } = this.state; + _tribbleValue: tribbleValue = 50, + _verticalValue: verticalValue = 0, + _verticalInvalid: verticalInvalid = false + } = this; return v('div', [ v('label', [ diff --git a/src/splitpane/example/index.ts b/src/splitpane/example/index.ts index 35a8ae549e..71d0294a98 100644 --- a/src/splitpane/example/index.ts +++ b/src/splitpane/example/index.ts @@ -1,14 +1,20 @@ +import { deepAssign } from '@dojo/core/lang'; import { DNode } from '@dojo/widget-core/interfaces'; import { WidgetBase } from '@dojo/widget-core/WidgetBase'; import { WidgetProperties } from '@dojo/widget-core/interfaces'; -import { StatefulMixin } from '@dojo/widget-core/mixins/Stateful'; import { ProjectorMixin } from '@dojo/widget-core/mixins/Projector'; import { v, w } from '@dojo/widget-core/d'; import SplitPane, { Direction } from '../../splitpane/SplitPane'; import dojoTheme from '../../themes/dojo/theme'; -export class App extends StatefulMixin(WidgetBase) { +export class App extends WidgetBase { private _theme: {}; + private state: any = {}; + + public setState(state: any) { + this.state = deepAssign(this.state, state); + this.invalidate(); + } themeChange(event: Event) { const checked = ( event.target).checked; diff --git a/src/tabpane/example/index.ts b/src/tabpane/example/index.ts index b4947374ef..612f865bd5 100644 --- a/src/tabpane/example/index.ts +++ b/src/tabpane/example/index.ts @@ -1,7 +1,7 @@ import { DNode } from '@dojo/widget-core/interfaces'; import { includes } from '@dojo/shim/array'; +import { deepAssign } from '@dojo/core/lang'; import { ProjectorMixin } from '@dojo/widget-core/mixins/Projector'; -import { StatefulMixin } from '@dojo/widget-core/mixins/Stateful'; import { v, w } from '@dojo/widget-core/d'; import { WidgetBase } from '@dojo/widget-core/WidgetBase'; import { WidgetProperties } from '@dojo/widget-core/interfaces'; @@ -18,8 +18,26 @@ function refreshData() { }); } -export class App extends StatefulMixin(WidgetBase) { +interface State { + align: Align; + closedKeys: string[]; + loading: boolean; + activeIndex: number; +} + +export class App extends WidgetBase { private _theme: {}; + private _state: State = { + align: Align.top, + closedKeys: [], + loading: false, + activeIndex: 0 + }; + + private setState(state: Partial) { + this._state = deepAssign(this._state, state); + this.invalidate(); + } themeChange(event: Event) { const checked = ( event.target).checked; @@ -51,7 +69,7 @@ export class App extends StatefulMixin(WidgetBase) { align, closedKeys = [], loading - } = this.state; + } = this._state; return v('div', { classes: { example: true } diff --git a/src/textarea/example/index.ts b/src/textarea/example/index.ts index e909e31463..4144fa23c8 100644 --- a/src/textarea/example/index.ts +++ b/src/textarea/example/index.ts @@ -1,14 +1,15 @@ import { WidgetBase } from '@dojo/widget-core/WidgetBase'; import { WidgetProperties, TypedTargetEvent } from '@dojo/widget-core/interfaces'; import { ProjectorMixin } from '@dojo/widget-core/mixins/Projector'; -import { StatefulMixin } from '@dojo/widget-core/mixins/Stateful'; import { v, w } from '@dojo/widget-core/d'; import Textarea from '../../textarea/Textarea'; import dojoTheme from '../../themes/dojo/theme'; -export const AppBase = StatefulMixin(WidgetBase); -export class App extends AppBase { +export class App extends WidgetBase { private _theme: {}; + private _value1: string; + private _value2: string; + private _invalid = false; themeChange(event: TypedTargetEvent) { const checked = event.target.checked; @@ -32,9 +33,10 @@ export class App extends AppBase { rows: 8, placeholder: 'Hello, World', label: 'Type Something', - value: this.state.value1, + value: this._value1, onChange: (event: TypedTargetEvent) => { - this.setState({ value1: event.target.value }); + this._value1 = event.target.value; + this.invalidate(); }, theme: this._theme }), @@ -55,12 +57,13 @@ export class App extends AppBase { rows: 8, label: 'Required', required: true, - value: this.state.value2, - invalid: this.state.invalid, + value: this._value2, + invalid: this._invalid, onChange: (event: TypedTargetEvent) => { const value = event.target.value; - this.setState({ value2: value }); - this.setState({ invalid: value.trim().length === 0 }); + this._value2 = value; + this._invalid = value.trim().length === 0; + this.invalidate(); }, theme: this._theme }) diff --git a/src/textinput/example/index.ts b/src/textinput/example/index.ts index f05280d198..8b0a2ef6ca 100644 --- a/src/textinput/example/index.ts +++ b/src/textinput/example/index.ts @@ -1,14 +1,17 @@ import { WidgetBase } from '@dojo/widget-core/WidgetBase'; import { WidgetProperties, TypedTargetEvent } from '@dojo/widget-core/interfaces'; -import { StatefulMixin } from '@dojo/widget-core/mixins/Stateful'; import { ProjectorMixin } from '@dojo/widget-core/mixins/Projector'; import { v, w } from '@dojo/widget-core/d'; import TextInput from '../../textinput/TextInput'; import dojoTheme from '../../themes/dojo/theme'; -export const AppBase = StatefulMixin(WidgetBase); -export class App extends AppBase { +export class App extends WidgetBase { private _theme: {}; + private _value1: string; + private _value2: string; + private _value3: string; + private _value4: string; + private _invalid = false; themeChange(event: Event) { const checked = ( event.target).checked; @@ -33,9 +36,10 @@ export class App extends AppBase { label: 'Name', type: 'text', placeholder: 'Hello, World', - value: this.state.value1, + value: this._value1, onChange: (event: TypedTargetEvent) => { - this.setState({ value1: event.target.value }); + this._value1 = event.target.value; + this.invalidate(); }, theme: this._theme }) @@ -50,9 +54,10 @@ export class App extends AppBase { content: 'Email (required)' }, required: true, - value: this.state.value2, + value: this._value2, onChange: (event: TypedTargetEvent) => { - this.setState({ value2: event.target.value }); + this._value2 = event.target.value; + this.invalidate(); }, theme: this._theme }) @@ -68,9 +73,10 @@ export class App extends AppBase { before: false, hidden: true }, - value: this.state.value3, + value: this._value3, onChange: (event: TypedTargetEvent) => { - this.setState({ value3: event.target.value }); + this._value3 = event.target.value; + this.invalidate(); }, theme: this._theme }) @@ -93,12 +99,13 @@ export class App extends AppBase { key: 't5', type: 'text', label: 'Type "foo" or "bar"', - value: this.state.value4, - invalid: this.state.invalid, + value: this._value4, + invalid: this._invalid, onChange: (event: TypedTargetEvent) => { const value = event.target.value; - this.setState({ value4: value }); - this.setState({ invalid: value.toLowerCase() !== 'foo' && value.toLowerCase() !== 'bar' }); + this._value4 = value; + this._invalid = value.toLowerCase() !== 'foo' && value.toLowerCase() !== 'bar'; + this.invalidate(); }, theme: this._theme }) diff --git a/src/timepicker/example/index.ts b/src/timepicker/example/index.ts index 68ba0501ab..1adb3db05c 100644 --- a/src/timepicker/example/index.ts +++ b/src/timepicker/example/index.ts @@ -1,7 +1,6 @@ import { getDateFormatter } from '@dojo/i18n/date'; import { DNode } from '@dojo/widget-core/interfaces'; import { ProjectorMixin } from '@dojo/widget-core/mixins/Projector'; -import { StatefulMixin } from '@dojo/widget-core/mixins/Stateful'; import { theme, ThemeableMixin, ThemeableProperties } from '@dojo/widget-core/mixins/Themeable'; import { v, w } from '@dojo/widget-core/d'; import { WidgetBase } from '@dojo/widget-core/WidgetBase'; @@ -16,11 +15,15 @@ const TODAY = new Date(); const getEnglishTime = getDateFormatter({ time: 'short' }); @theme(baseCss) -export class App extends ThemeableMixin(StatefulMixin(WidgetBase)) { +export class App extends ThemeableMixin(WidgetBase) { private _theme: {}; + private _options: TimeUnits[]; + private _values: any; + private _invalid = false; onRequestOptions(value: string, options: TimeUnits[]) { - this.setState({ options }); + this._options = options; + this.invalidate(); } themeChange(event: Event) { @@ -29,6 +32,11 @@ export class App extends ThemeableMixin(StatefulMixin(WidgetBase)) this.setState({ 'value1': value }), + onChange: (value: string) => { + this._setValue('value1', value); + }, onRequestOptions: (value: string, options: TimeUnits[]) => { if (!value) { - return this.setState({ options }); + this._options = options; } + else { - const matching = options.filter(option => { - const { hour, minute = 0 } = option; - const hours = hour >= 10 ? hour : `0${hour}`; - const minutes = minute >= 10 ? minute : `0${minute}`; - return `${hours}:${minutes}`.indexOf(value) === 0; - }); + const matching = options.filter(option => { + const { hour, minute = 0 } = option; + const hours = hour >= 10 ? hour : `0${hour}`; + const minutes = minute >= 10 ? minute : `0${minute}`; + return `${hours}:${minutes}`.indexOf(value) === 0; + }); - this.setState({ - options: matching.length ? matching : options - }); + this._options = matching.length ? matching : options; + } + this.invalidate(); }, - options: this.state.options, + options: this._options, step: 1800, theme: this._theme, - value: this.state['value1'] + value: this._values['value1'] }), v('h3', [ 'Open on focus' ]), @@ -83,12 +94,14 @@ export class App extends ThemeableMixin(StatefulMixin(WidgetBase)) this.setState({ 'value2': value }), + onChange: (value: string) => { + this._setValue('value2', value); + }, onRequestOptions: this.onRequestOptions, - options: this.state.options, + options: this._options, step: 1800, theme: this._theme, - value: this.state['value2'] + value: this._values['value2'] }), v('h3', [ 'Disabled menu items' ]), @@ -103,12 +116,14 @@ export class App extends ThemeableMixin(StatefulMixin(WidgetBase)) option.hour >= 12, key: '3', - onChange: (value: string) => this.setState({ 'value3': value }), + onChange: (value: string) => { + this._setValue('value3', value); + }, onRequestOptions: this.onRequestOptions, - options: this.state.options, + options: this._options, step: 3600, theme: this._theme, - value: this.state['value3'] + value: this._values['value3'] }), v('h3', [ 'Disabled' ]), @@ -140,12 +155,14 @@ export class App extends ThemeableMixin(StatefulMixin(WidgetBase)) this.setState({ 'value6': value }), + onChange: (value: string) => { + this._setValue('value6', value); + }, onRequestOptions: this.onRequestOptions, - options: this.state.options, + options: this._options, step: 1800, theme: this._theme, - value: this.state['value6'] + value: this._values['value6'] }), v('h3', [ 'Required and validated' ]), @@ -154,21 +171,22 @@ export class App extends ThemeableMixin(StatefulMixin(WidgetBase)) this.setState({ - invalid: value.trim().length === 0 - }), - onChange: (value: string) => this.setState({ - 'value7': value, - invalid: value.trim().length === 0 - }), + onBlur: (value: string) => { + this._invalid = value.trim().length === 0; + this.invalidate(); + }, + onChange: (value: string) => { + this._invalid = value.trim().length === 0; + this._setValue('value7', value); + }, onRequestOptions: this.onRequestOptions, - options: this.state.options, + options: this._options, step: 1800, theme: this._theme, - value: this.state['value7'] + value: this._values['value7'] }), v('h3', [ 'One second increment' ]), @@ -183,13 +201,15 @@ export class App extends ThemeableMixin(StatefulMixin(WidgetBase)) this.setState({ 'value8': value }), + options: this._options, + onChange: (value: string) => { + this._setValue('value8', value); + }, onRequestOptions: this.onRequestOptions, start: '12:00:00', step: 1, theme: this._theme, - value: this.state['value8'] + value: this._values['value8'] }), v('h3', [ 'Use 12-hour time' ]), @@ -208,12 +228,14 @@ export class App extends ThemeableMixin(StatefulMixin(WidgetBase)) this.setState({ 'value9': value }), + onChange: (value: string) => { + this._setValue('value9', value ); + }, onRequestOptions: this.onRequestOptions, - options: this.state.options, + options: this._options, step: 1800, theme: this._theme, - value: this.state['value9'] + value: this._values['value9'] }), v('h3', [ 'Native ``' ]), @@ -223,13 +245,15 @@ export class App extends ThemeableMixin(StatefulMixin(WidgetBase)) this.setState({ 'value10': value }), + onChange: (value: string) => { + this._setValue('value10', value); + }, step: 1800, theme: this._theme, useNativeElement: true, invalid: true, label: 'foo', - value: this.state['value10'] + value: this._values['value10'] }) ]); } diff --git a/src/titlepane/example/index.ts b/src/titlepane/example/index.ts index 8bc67fab48..018b44ad3d 100644 --- a/src/titlepane/example/index.ts +++ b/src/titlepane/example/index.ts @@ -1,5 +1,4 @@ import { ProjectorMixin } from '@dojo/widget-core/mixins/Projector'; -import { StatefulMixin } from '@dojo/widget-core/mixins/Stateful'; import { v, w } from '@dojo/widget-core/d'; import { WidgetBase } from '@dojo/widget-core/WidgetBase'; import { WidgetProperties, TypedTargetEvent } from '@dojo/widget-core/interfaces'; @@ -7,8 +6,10 @@ import { WidgetProperties, TypedTargetEvent } from '@dojo/widget-core/interfaces import TitlePane from '../TitlePane'; import dojoTheme from '../../themes/dojo/theme'; -export class App extends StatefulMixin(WidgetBase) { +export class App extends WidgetBase { private _theme: {}; + private _t2Open = true; + private _t3Open = false; themeChange(event: TypedTargetEvent) { const checked = event.target.checked; @@ -18,9 +19,9 @@ export class App extends StatefulMixin(WidgetBase) { render() { const { - t2open = true, - t3open = false - } = this.state; + _t2Open, + _t3Open + } = this; return v('div', { styles: { @@ -67,14 +68,16 @@ export class App extends StatefulMixin(WidgetBase) { w(TitlePane, { headingLevel: 2, key: 'titlePane2', - open: t2open, + open: _t2Open, theme: this._theme, title: 'TitlePanel Widget (closeable)', onRequestClose: () => { - this.setState({ t2open: false }); + this._t2Open = false; + this.invalidate(); }, onRequestOpen: () => { - this.setState({ t2open: true }); + this._t2Open = true; + this.invalidate(); } }, [ v('div', { @@ -96,14 +99,16 @@ export class App extends StatefulMixin(WidgetBase) { v('div', { id: 'titlePane3' }, [ w(TitlePane, { key: 'titlePane3', - open: t3open, + open: _t3Open, theme: this._theme, title: 'TitlePanel Widget with open=false', onRequestClose: () => { - this.setState({ t3open: false }); + this._t3Open = false; + this.invalidate(); }, onRequestOpen: () => { - this.setState({ t3open: true }); + this._t3Open = true; + this.invalidate(); } }, [ v('div', { From 71c941bd780edb9774b22a45ccef4344a6251819 Mon Sep 17 00:00:00 2001 From: Anthony Gubler Date: Fri, 30 Jun 2017 19:27:03 +0100 Subject: [PATCH 3/6] changes for ts 2.4 and latest widget-core --- package.json | 2 +- src/calendar/Calendar.ts | 4 ++-- src/calendar/tests/unit/MonthPicker.ts | 16 ++++++++++------ src/combobox/ComboBox.ts | 4 ++-- src/select/Select.ts | 4 ++-- src/titlepane/tests/unit/TitlePane.ts | 18 +++++++++++------- 6 files changed, 28 insertions(+), 20 deletions(-) diff --git a/package.json b/package.json index d891b1b208..6f8e7a38c3 100644 --- a/package.json +++ b/package.json @@ -40,6 +40,6 @@ "grunt-dojo2": "latest", "intern": "^3.4.1", "sinon": "^1.17.6", - "typescript": "~2.3.2" + "typescript": "~2.4.1" } } diff --git a/src/calendar/Calendar.ts b/src/calendar/Calendar.ts index 97c5e6129a..cb3d32037a 100644 --- a/src/calendar/Calendar.ts +++ b/src/calendar/Calendar.ts @@ -91,14 +91,14 @@ export default class Calendar extends CalendarBase { super(); this._registry = this._createRegistry(CalendarCell); - this.registries.add(this._registry); + this.getRegistries().add(this._registry); } @diffProperty('customDateCell', reference) protected onPropertiesChanged(previousProperties: any, newProperties: any) { const { customDateCell = CalendarCell } = newProperties; const registry = this._createRegistry(customDateCell); - this.registries.replace(this._registry, registry); + this.getRegistries().replace(this._registry, registry); this._registry = registry; } diff --git a/src/calendar/tests/unit/MonthPicker.ts b/src/calendar/tests/unit/MonthPicker.ts index 0f8ab4a87e..1119fd829d 100644 --- a/src/calendar/tests/unit/MonthPicker.ts +++ b/src/calendar/tests/unit/MonthPicker.ts @@ -143,6 +143,10 @@ const expected = function(widget: any, open = false) { ]); }; +interface TestEventInit extends EventInit { + which: number; +} + registerSuite({ name: 'Calendar MonthPicker', @@ -219,7 +223,7 @@ registerSuite({ }); // escape key - widget.sendEvent('keydown', { + widget.sendEvent('keydown', { eventInit: { which: Keys.Escape }, @@ -229,7 +233,7 @@ registerSuite({ // enter key closed = false; - widget.sendEvent('keydown', { + widget.sendEvent('keydown', { eventInit: { which: Keys.Enter }, @@ -239,7 +243,7 @@ registerSuite({ // space key closed = false; - widget.sendEvent('keydown', { + widget.sendEvent('keydown', { eventInit: { which: Keys.Space }, @@ -249,7 +253,7 @@ registerSuite({ // random key closed = false; - widget.sendEvent('keydown', { + widget.sendEvent('keydown', { eventInit: { which: Keys.PageDown }, @@ -266,7 +270,7 @@ registerSuite({ onRequestYearChange: (year: number) => { currentYear = year; } }); - widget.sendEvent('keydown', { + widget.sendEvent('keydown', { eventInit: { which: Keys.Right }, @@ -275,7 +279,7 @@ registerSuite({ assert.strictEqual(currentYear, 2018, 'Right arrow key increased year'); - widget.sendEvent('keydown', { + widget.sendEvent('keydown', { eventInit: { which: Keys.Left }, diff --git a/src/combobox/ComboBox.ts b/src/combobox/ComboBox.ts index 8369c74b35..ab84079e99 100644 --- a/src/combobox/ComboBox.ts +++ b/src/combobox/ComboBox.ts @@ -91,7 +91,7 @@ export default class ComboBox extends ComboBoxBase { super(); this._registry = this._createRegistry(ResultItem, ResultMenu); - this.registries.add(this._registry); + this.getRegistries().add(this._registry); } private _closeMenu() { @@ -318,7 +318,7 @@ export default class ComboBox extends ComboBoxBase { } = newProperties; const registry = this._createRegistry(customResultItem, customResultMenu); - this.registries.replace(this._registry, registry); + this.getRegistries().replace(this._registry, registry); this._registry = registry; } diff --git a/src/select/Select.ts b/src/select/Select.ts index 9c9e7c2b75..3afdf6dc59 100644 --- a/src/select/Select.ts +++ b/src/select/Select.ts @@ -80,7 +80,7 @@ export default class Select extends SelectBase { super(); this._registry = this._createRegistry(SelectOption); - this.registries.add(this._registry); + this.getRegistries().add(this._registry); } private _createRegistry(customOption: any) { @@ -235,7 +235,7 @@ export default class Select extends SelectBase { } = newProperties; const registry = this._createRegistry(customOption); - this.registries.replace(this._registry, registry); + this.getRegistries().replace(this._registry, registry); this._registry = registry; } diff --git a/src/titlepane/tests/unit/TitlePane.ts b/src/titlepane/tests/unit/TitlePane.ts index 828c7563e7..175d038ef4 100644 --- a/src/titlepane/tests/unit/TitlePane.ts +++ b/src/titlepane/tests/unit/TitlePane.ts @@ -11,6 +11,10 @@ const isNonEmptyString = compareProperty((value: any) => { return typeof value === 'string' && value.length > 0; }); +interface TestEventInit extends EventInit { + keyCode: number; +} + let titlePane: Harness; registerSuite({ name: 'TitlePane', @@ -172,7 +176,7 @@ registerSuite({ title: 'test' }); titlePane.getRender(); - titlePane.sendEvent('keyup', { + titlePane.sendEvent('keyup', { eventInit: { keyCode: Keys.Enter }, selector: `.${css.title}` }); @@ -185,7 +189,7 @@ registerSuite({ title: 'test' }); titlePane.getRender(); - titlePane.sendEvent('keyup', { + titlePane.sendEvent('keyup', { eventInit: { keyCode: Keys.Enter }, selector: `.${css.title}` }); @@ -205,14 +209,14 @@ registerSuite({ }; titlePane.setProperties(props); - titlePane.sendEvent('keyup', { + titlePane.sendEvent('keyup', { eventInit: { keyCode: Keys.Enter }, selector: `.${css.title}` }); assert.strictEqual(openCount, 1, 'onRequestOpen should be called on title enter keyup'); titlePane.setProperties(props); - titlePane.sendEvent('keyup', { + titlePane.sendEvent('keyup', { eventInit: { keyCode: Keys.Space }, selector: `.${css.title}` }); @@ -231,14 +235,14 @@ registerSuite({ }; titlePane.setProperties(props); - titlePane.sendEvent('keyup', { + titlePane.sendEvent('keyup', { eventInit: { keyCode: Keys.Enter }, selector: `.${css.title}` }); assert.strictEqual(closeCount, 1, 'onRequestClose should be called on title enter keyup'); titlePane.setProperties(props); - titlePane.sendEvent('keyup', { + titlePane.sendEvent('keyup', { eventInit: { keyCode: Keys.Space }, selector: `.${css.title}` }); @@ -261,7 +265,7 @@ registerSuite({ for (let i = 8; i < 223; i++) { if (i !== Keys.Enter && i !== Keys.Space) { - titlePane.sendEvent('keyup', { + titlePane.sendEvent('keyup', { eventInit: { keyCode: i }, selector: `.${css.title}` }); From 22c7651d8891558493fe7a8a30f45d37f5a5f0b8 Mon Sep 17 00:00:00 2001 From: Anthony Gubler Date: Thu, 6 Jul 2017 09:52:18 +0100 Subject: [PATCH 4/6] do not initialise button press state --- src/button/example/index.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/button/example/index.ts b/src/button/example/index.ts index 10d28e4865..39d891d260 100644 --- a/src/button/example/index.ts +++ b/src/button/example/index.ts @@ -7,7 +7,7 @@ import dojoTheme from '../../themes/dojo/theme'; export class App extends WidgetBase { private _theme: {}; - private _buttonPressed = false; + private _buttonPressed: boolean; themeChange(event: TypedTargetEvent) { const checked = event.target.checked; From eb2675a6e815b5b2e268b0e78e34df3fe64f891f Mon Sep 17 00:00:00 2001 From: Anthony Gubler Date: Thu, 6 Jul 2017 09:57:08 +0100 Subject: [PATCH 5/6] use defaulted variable --- src/radio/example/index.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/radio/example/index.ts b/src/radio/example/index.ts index 06019d63c2..6fd538ad7c 100644 --- a/src/radio/example/index.ts +++ b/src/radio/example/index.ts @@ -41,7 +41,7 @@ export class App extends WidgetBase { v('legend', {}, ['Set of radio buttons with first option selected']), w(Radio, { key: 'r1', - checked: this._inputValue === 'first', + checked: _inputValue === 'first', value: 'first', label: 'First option', name: 'sample-radios', From cd7fe0cb61279346f41f8304eac95a878c723d6b Mon Sep 17 00:00:00 2001 From: Anthony Gubler Date: Thu, 6 Jul 2017 10:30:19 +0100 Subject: [PATCH 6/6] do not initialise button press state --- src/textinput/example/index.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/textinput/example/index.ts b/src/textinput/example/index.ts index 8b0a2ef6ca..fbc376d30c 100644 --- a/src/textinput/example/index.ts +++ b/src/textinput/example/index.ts @@ -11,7 +11,7 @@ export class App extends WidgetBase { private _value2: string; private _value3: string; private _value4: string; - private _invalid = false; + private _invalid: boolean; themeChange(event: Event) { const checked = ( event.target).checked;