Widgets 6 to 7 Migration Guide
June 25, 2020 ยท View on GitHub
Breaking changes
Removal of touch/mouse/pointer events
We have standardized mouse / touch events to use pointer events and removed a large number of callbacks. For example, text-input now provides onOver / onOut events rather than mouseIn / mouseOut which signify the cross device nature of the pointer events being used.
Standardization of input/value/change
We have consolidated the use of onInput / onChange / etc to a consistent onValue callback. All widgets returning a value will do so using this callback. In addition to this change, any callbacks which previously returned a value or a key such as onChange / onBlur have either been removed or have been changed to return zero parameters.
To match the use of onValue, all widgets that accept a value now either take a value or initialValue property (in the case of partially controlled widgets). This will make it easier and more consistent to use the widget library.
Partially controlled pattern
In an effort to make widgets easier and simpler to use out of the box we have changed many of our form widgets to use a partially controlled pattern. This means widgets that accept initialValue will manage their own value internally. They will still report back value changes via the onValue callback but you do not need to keep setting value on the widget. The same is true for widgets that accept an onValidate callback but do not accept valid. These widgets will self validate and inform you of their validation state.
Validated widgets
Many of our form widgets are now capable of validating themselves. In many cases this is done in an uncontrolled way meaning the widget will display its valid state / error message and will call the onValidate callback when valid state changes.
Individual Widget Changes
AccordionPane
- Renamed to
Accordion.
Property changes
Added properties
exclusive?: boolean;- This property only allows one open child pane at a time.
Changed properties
children: AccordionPaneChildren;- This property no longer accepts
TitlePanewidgets. - This property accepts a renderer function that returns child panes.
- Child panes use renderer function arguments as properties.
Paneis exported fromAccordion
- This property no longer accepts
Removed properties
onRequestClose?(key: string): void- This property was removed altogether.
- Child panes can use
onCloseinstead.
onRequestOpen?(key: string): void- This property was removed altogether.
- Child panes can use
onOpeninstead.
openKeys?: string[]- This property was removed altogether.
- Child pane open state is now internally managed.
- Child panes can use
initialOpento set initial open state.
Changes in behavior
The Accordion widget is now uncontrolled by default, meaning it manages its own child pane open state internally. Child panes can use an initialOpen property to set individual initial open state. Child panes can also use onOpen and onClose properties to detect when this open state changes.
The Accordion now uses a child renderer function to determine its child panes. This means that a function is passed as the widget's only child, and that function receives onOpen, onClose, and open arguments to be used as properties each returned pane. Child panes should be Pane widgets, a convenience wrapper around TitlePane with features specific to Accordion.
Example of migration from v6 to v7
v6 Example
<AccordionPane
onRequestClose={key => icache.set('keys', icache.get('keys').filter(k !== key))}
onRequestOpen={key => icache.set('keys', [...icache.get('keys'), key])}
openKeys={icache.get('keys')}
>
<TitlePane
title="Title"
key="pane"
>
Content
</TitlePane>
</AccordionPane>
v7 Example
<Accordion>
{(onOpen, onClose, open) => ([
<Pane
key="pane"
onOpen={onOpen('pane')}
onClose={onClose('pane')}
open={open('pane')}
>
{{
title: 'Title',
content: 'Content'
}}
</Pane>
])}
</Accordion>
Latest example can be found at widgets.dojo.io/#widget/accordion/overview
Button
Property changes
Changed properties
- onDown?(): void;
- Handler for events triggered by pointer down.
- Replaces previous down event handlers.
Removed properties
- popup?: { expanded?: boolean; id?: string } | boolean;
- Popup functionality was removed from
Button. - The
TriggerPopupwidget provides popup functionality.
- Popup functionality was removed from
- onInput?(value?: string | number | boolean): void;
- Not applicable to a button.
- onChange?(value?: string | number | boolean): void;
- Not applicable to a button.
- The following interaction events were replaced by onDown:
- onMouseDown?(): void;
- onMouseUp?(): void;
- onTouchStart?(): void;
- onTouchEnd?(): void;
- onTouchCancel?(): void;
- onMouseDown?(): void;
- onMouseUp?(): void;
- onTouchStart?(): void;
- onTouchEnd?(): void;
- onTouchCancel?(): void;
Example of migration from v6 to v7
v6 Example
<Button onMouseDown={() => {console.log('Down')}}>Example Button</Button>
v7 Example
<Button onDown={() => {console.log('Down')}}>Example Button</Button>
Latest example can be found at widgets.dojo.io/#widget/button/overview
Calendar
Property changes
Changed properties
- initialValue?: Date
- This property can be used to provide an initial value or can be used to partially control the component, which responds to changes in this value
- value?: Date
- This property replaced
selectedDate
- This property replaced
- onValue?(value: Date): void
- This property replaced
onDateSelect - The name was changed to follow a more consistent pattern
- This property replaced
- initialMonth?: number
- This property can be used to specify the initial month that should be displayed or can be used together with
onMonthto partially control the month displayed, which will responod to changes in this value
- This property can be used to specify the initial month that should be displayed or can be used together with
- onMonth?(month: number): void
- This property replaced
onMonthChange - The name was changed to follow a more consistent pattern
- This property replaced
- initialYear?: number
- This property can be used to specify the initial year that should be displayed or can be used together with
onYearto partially control the year displayed, which will respond to changes in this value
- This property can be used to specify the initial year that should be displayed or can be used together with
- onYear?(year: number): void
- This property replaced
onYearChange - The name was changed to follow a more consistent pattern
- This property replaced
Changes in behavior
The calendar widget is now uncontrolled by default. Initial values can be provided but the calendar will maintain its own internal state, tracking the displayed month and year and the currently selected value. The calendar can be partially controlled using the initial properties as it will update when those values change. For use cases where the component needs to be fully controlled, the value, month, and year properties can be used.
Example of migration from v6 to v7
v6 Example
const selectedDate = icache.getOrSet('date', new Date());
const month = icache.getOrSet('month', selectedDate.getMonth());
const year = icache.getOrSet('year', selectedDate.getFullYear());
<Calendar
selectedDate={selectedDate}
month={month}
year={year}
onDateSelect={date => {
icache.set('date', date);
}}
onMonthChange={month => {
icache.set('month', month);
}}
onYearChange={year => {
icache.set('year', year);
}}
/>
v7 Example
<Calendar
onValue={date => {
icache.set('date', date);
}}
/>
Latest example can be found at widgets.dojo.io/#widget/calendar/overview
Checkbox
Property changes
Changed properties
- onBlur: () => void;
- this prop now is passed zero arguments, whereas previously it was passed the current
valueandcheckedproperty values.
- this prop now is passed zero arguments, whereas previously it was passed the current
- onFocus: () => void;
- this prop now is passed zero arguments, whereas previously it was passed the current
valueandcheckedproperty values.
- this prop now is passed zero arguments, whereas previously it was passed the current
Removed properties
- label: string;
- Removed in favor of using a child to render the label
- onLabel: DNode
- Removed in favor of using a child renderer
- offLabel: DNode
- Removed in favor of using a child renderer
- mode: 'normal' | 'toggle'
- "toggle" mode has been split into the
switchwidget (see below)
- "toggle" mode has been split into the
- onChange: (value: string, checked: boolean) => void;
- replaced by
onValue(checked: boolean) - onClick: (value: string, checked: boolean) => void;
- replaced by
onValue(checked: boolean)
Example of migration from v6 to v7
v6 Example
import { create, tsx } from '@dojo/framework/core/vdom';
import icache from '@dojo/framework/core/middleware/icache';
import Checkbox from '@dojo/widgets/checkbox';
const factory = create({ icache });
export default factory(function CheckboxExample({ middleware: { icache } }) {
const checkboxStates = icache.getOrSet('checkboxStates', {});
return [
<Checkbox
checked={checked.checkbox0}
label="v6 Checkbox Example"
value="checkbox0"
onChange={(value, checked) => {
icache.set('checkboxStates', {
...checkboxStates,
[value]: checked
});
}}
/>,
// other checkboxes...
];
});
v7 Example
import { create, tsx } from '@dojo/framework/core/vdom';
import icache from '@dojo/framework/core/middleware/icache';
import Checkbox from '@dojo/widgets/checkbox';
const factory = create({ icache });
export default factory(function CheckboxExample({ middleware: { icache } }) {
const checkboxStates = icache.getOrSet('checkboxStates', {});
return [
<Checkbox
checked={icache.get('isChecked0')}
onValue={(checked) => {
icache.set('isChecked0', checked);
}}
>
v7 Checkbox Example
</Checkbox>,
// other checkboxes...
];
});
Latest example can be found at widgets.dojo.io/#widget/checkbox/overview
Dialog
Property changes
Changed properties
title?: DNode;- Title is now specified in the child function and not passed as a property.
modal?: boolean;- The modal property is now only valid when role="dialog"
Removed properties
underlayEnterAnimation- Replaced by theming
underlayEnterclass.
- Replaced by theming
underlayExitAnimation- Replaced by theming
underlayExitclass.
- Replaced by theming
enterAnimation- Replaced by theming
enterclass
- Replaced by theming
exitAnimation- Replaced by theming
exitclass
- Replaced by theming
Changes in behavior
Dialog contents, title, and actions are now specified via a child function. Previously, the title was specified via a property and the dialog contents where passed as the children of the Dialog. Dialog actions are nodes that appear below the dialog contents, like cancel / ok buttons.
Example of migration from v6 to v7
v6 Example
<Dialog
title='Basic Dialog'
open={this._open}
onRequestClose={() => {
this._open = false;
this.meta(Focus).set('button');
this.invalidate();
}}
>
Lorem ipsum dolor sit amet, consectetur adipiscing elit.
Quisque id purus ipsum. Aenean ac purus purus.
Nam sollicitudin varius augue, sed lacinia felis tempor in.
</Dialog>
v7 Example
<Dialog open={isOpen} onRequestClose={() => icache.set('isOpen', false)}>
{{
title: 'Basic Dialog',
content: (
<virtual>
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Quisque id
purus ipsum. Aenean ac purus purus. Nam sollicitudin varius augue, sed
lacinia felis tempor in.
</virtual>
)
}}
</Dialog>
Latest example can be found at widgets.dojo.io/#widget/dialog/overview
Toolbar
- Renamed to
Header.
Property changes
Added properties
sticky?: boolean- This property fixed the header to the top of a view.
Changed properties
children: HeaderChildren- This property no longer accepts
DNodeactions. - This property accepts a child renderer object.
- Leading, trailing, title, and actions are set using this renderer.
- This property no longer accepts
Removed properties
align?: Align- This property was removed altogether.
- Alignment functionality is no longer supported.
collapseWidth?: number- This property was removed altogether.
- Collapse functionality is no longer supported.
onCollapse?(collapsed: boolean): void- This property was removed altogether.
- Collapse functionality is no longer supported.
heading?: string- This property was removed altogether.
- The header title is now set using a child renderer.
Changes in behavior
The Header now uses a child renderer object to determine its leading content, trailing content, title, and action items. This means that an object is passed as the widget's only child with keys for leading , trailing, title, and actions, each of which return elements to render accordingly.
The Header no longer auto-collapses action items into a SlidePane. Instead, to be more aligned with future Dojo application architecture, media-based middleware can be used to responsively change the Header out for a different widget depending on available space.
Example of migration from v6 to v7
v6 Example
<Toolbar
align={Align.right}
collapseWidth={700}
heading="Title"
onCollapse={() => { console.log('collapsed'); }}
>
<a href="#foo">Foo</a>
<a href="#bar">Bar</a>
<a href="#baz">Baz</a>
</Toolbar>
v7 Example
<Header>
{{
title: 'Title',
actions: [
<Link to="#foo">Foo</Link>,
<Link to="#bar">Bar</Link>,
<Link to="#baz">Baz</Link>
]
}}
</Header>
Example of responsive toolbar behaviour using Header and SlidePane
import { create, tsx } from '@dojo/framework/core/vdom';
import theme from '@dojo/framework/core/middleware/theme';
import breakpoint from '@dojo/framework/core/middleware/breakpoint';
import icache from '@dojo/framework/core/middleware/icache';
import { Header } from '@dojo/widgets/header';
import { SlidePane } from '@dojo/widgets/slide-pane';
import { Icon } from '@dojo/widgets/icon';
import * as css from './CollapsingHeader.m.css';
const factory = create({ theme, breakpoint, icache });
export default factory(function CollapsingHeader({ middleware: { theme, breakpoint, icache } }) {
const size = breakpoint.get('root');
const open = icache.getOrSet('open', false);
const collapse = size && (size.breakpoint === 'SM' || size.breakpoint === 'MD');
const appTitle = 'My App';
const actions = (
<virtual>
<a classes={css.action}>foo</a>
<a classes={css.action}>bar</a>
<a classes={css.action}>baz</a>
</virtual>
);
return (
<div key='root' classes={[css.root, theme.variant()]}>
<Header>{{
title: appTitle,
actions: !collapse && <div classes={css.headerActions}>{ actions }</div>,
leading: collapse &&
<button onclick={() => { icache.set('open', !open) }} type='button'>
<Icon size='large' type='barsIcon' />
</button>
}}</Header>
{collapse &&
<SlidePane title={appTitle} open={open} onRequestClose={() => { icache.set('open', false)}}>
<div classes={css.collapsedActions}>
{ actions }
</div>
</SlidePane>
}
</div>
);
});
.headerActions {
display: flex;
flex-direction: row;
}
.collapsedActions {
display: flex;
flex-direction: column;
}
.action {
padding: 10px;
}
Latest example can be found at widgets.dojo.io/#widget/header/overview
Label
Property changes
Removed properties
invalid?: boolean- replaced by
valid?: boolean - inverted validation API for consistency
- replaced by
Example of migration from v6 to v7
v6 Example
<Label invalid={true}>Invalid Label</Label>
v7 Example
<Label valid={false}>Invalid Label</Label>
Latest example can be found at widgets.dojo.io/#widget/label/overview
ListBox
- Rewritten and renamed to
List - Now uses a
resourceand thedatamiddleware.
Property changes
Additional Mandatory Properties
onValue(value: string)- this is the callback on value change.
resource- this is the data resource for the List to use to generate the list items
transform- a transform is required for the List as it uses a typed data middleware.
- a
defaultTransformis exported fromList
Changed properties
getOptionDisabled- replaced by
disabled(item: ListOption): booleancallback
- replaced by
optionData- replaced by
resource - widget is now data aware and uses
resources
- replaced by
visualFocus- replaced by
focusable: boolean. - determines if the List can be focused and capture key press events
- replaced by
onActiveIndexChange- only received the index of the item requesting to be made active
- keyboard navigation is now partially controlled, you need only pass the
onActiveIndexChange&activeIndexproperties if you wish to fully control them.
onOptionSelect- replaced by
onValuewhich returns the selected item value
- replaced by
getOptionSelected- replaced by partial control via internal state or fully controlled selections via
value&onValueproperties
- replaced by partial control via internal state or fully controlled selections via
Removed properties
multiselect: boolean;- list is now single select but can be used as part of a multiselect typeahead implementation
getOptionLabellabelis now passed via aListOptionfrom theresource. If a label is not passed, thevalueis used instead.
getOptionId- an id is generated and used internally for each list item.
tabIndex- the tab index is managed internally
- focus can be disabled via the
focusableproperty.
Changes in behavior
Example of migration from v6 to v7
v6 Example
<Listbox
key='listbox1'
activeIndex={this._listbox1Index}
widgetId='listbox1'
optionData={this._options}
getOptionLabel={(option: CustomOption) => option.value}
getOptionDisabled={(option: CustomOption) => !!option.disabled}
getOptionSelected={(option: CustomOption) => option.value === this._listbox1Value}
onActiveIndexChange={(index: number) => {
this._listbox1Index = index;
this.invalidate();
}}
onOptionSelect={(option: any, index: number) => {
this._listbox1Value = option.value;
this._options = [...this._options];
this.invalidate();
}}
></Listbox>
v7 Example
const animals = [{ value: 'cat' }, { value: 'dog' }, { value: 'mouse' }, { value: 'rat' }];
const resource = createResource(createMemoryTemplate());
<List
widgetId='listbox1'
initialValue='cat'
resource={{ resource: () => resource, data: animals }}
transform={defaultTransform}
onValue={(value: string) => {
icache.set('value', value);
}}
/>
Latest example can be found at widgets.dojo.io/#widget/list/overview
Progress
Property changes
Changed properties
output?: () => RenderResult;outputwas moved to a child renderer and should be handled in a child function.
Changes in behavior
Output is now handled via an optional child renderer of type RenderResult.
Example of migration from v6 to v7
v6 Example
<Progress
value={value}
max={max}
output={(value, percent) => `${value} of ${max} is ${percent}%`}
/>
v7 Example
<Progress value={value} max={max}>
{{
output: (value, percent) => `${value} of ${max} is ${percent}%`
}}
</Progress>
Latest example can be found at widgets.dojo.io/#widget/progress/overview
Radio
Property changes
Changed properties
label?: RenderResult;- Label is now handled in a child renderer. Child content of the Radio widget is displayed in a Label.
Removed properties
labelAfter?: boolean;- Removed in favor of a single label handled via a child renderer.
Changes in behavior
Label is now handled via an optional child renderer of type RenderResult.
Example of migration from v6 to v7
v6 Example
<Radio label={'Radio Button 1'} />
v7 Example
<Radio>Radio Button 1</Radio>
Latest example can be found at widgets.dojo.io/#widget/radio/overview
RangeSlider
Property changes
Changed properties
initialValue?: RangeValue- This property can be used to partially control the range slider by setting an initial value.
value?: RangeValue- The range-slider now internally manages its value by default and it is no longer necessary to pass the current value
- Passing a value allows the range-slider to be fully controlled
label?: RenderResult;- Replaced with a child renderer
output?(value: RangeValue): RenderResult;- Replaced with a child renderer
Removed properties
labelAfter- No longer supported
Changes in behavior
The range slider widget now internally manages its own value by default and can be changed via the initialValue property. The range slider can be fully controlled using the value property.
Example of migration from v6 to v7
v6 Example
<RangeSlider
onInput={(min: number, max: number) => {
this._state.value1Min = min;
this._state.value1Max = max;
this.invalidate();
}}
onChange={(min: number, max: number) => {
this._state.value1Min = min;
this._state.value1Max = max;
this.invalidate();
}}
/>
v7 Example
<RangeSlider
initialValue={{
min: 0,
max: 100
}}
/>
Latest example can be found at widgets.dojo.io/#widget/range-slider/overview
Select
- Now uses list, no longer supports using the native element.
NativeSelectis now it's own widget- Select now uses
resourceand thedatamiddleware.
Property changes
Changed properties
onValue: (value: string) => void;- Replaces
onChange
- Replaces
initialValue?: string;- Can be used to an initial value and then let the component act in an uncontrolled manner.
Removed properties
useNativeElement: boolean;- Native use case is now supported by its own widget
Changes in behavior
- Can now be used in an uncontrolled or controlled manner.
- Accepts a resource, please see
Listboxmigration for more information as this is used internally bySelect.
Example of migration from v6 to v7
v6 Example
<Select
onChange={value => {
icache.set('value', value);
}}
value={icache.get('value')}
/>
v7 Example
const animals = [{ value: 'cat' }, { value: 'dog' }, { value: 'mouse' }, { value: 'rat' }];
const resource = createResource(createMemoryTemplate());
<Select
initialValue='cat'
resource={{ resource: () => resource, data: animals }}
transform={defaultTransform}
onValue={(value: string) => {
icache.set('value', value);
}}
/>
Latest example can be found at widgets.dojo.io/#widget/select/overview
Example using select and resource within a class-based widget
To use a widget that requires a resource within a class-bassed widget, you must inject the resource middleware via a wrapping widget. An example of this approach can be seen below. (Example taken from github.com/agubler/dojo-resource-wrapper)
// Resource wrapper
import { create } from '@dojo/framework/core/vdom';
import { createResourceMiddleware } from '@dojo/framework/core/middleware/resources';
import { RenderResult } from '@dojo/framework/core/interfaces';
const resourceMiddleware = createResourceMiddleware();
const factory = create({ resource: resourceMiddleware }).children<(resource: ReturnType<typeof resourceMiddleware>['api']) => RenderResult>();
export default factory(function ResourceWrapper({ middleware: { resource }, children }) {
const [renderer] = children();
return renderer(resource);
});
// Resource wrapper use within a class
import renderer, { w, v } from '@dojo/framework/core/vdom';
import { uuid } from '@dojo/framework/core/util';
import WidgetBase from '@dojo/framework/core/WidgetBase';
import watch from '@dojo/framework/core/decorators/watch';
import Select from '@dojo/widgets/select';
import theme from '@dojo/widgets/theme/dojo';
import Registry from '@dojo/framework/core/Registry'
import { registerThemeInjector } from '@dojo/framework/core/mixins/Themed';
import { createMemoryResourceTemplate } from '@dojo/framework/core/middleware/resources';
import ResourceWrapper from './ResourceWrapper';
interface Animals {
value: string;
}
const template = createMemoryResourceTemplate<Animals>()
class App extends WidgetBase {
@watch()
private _selectedValue = '';
private _id = uuid();
private _onValue = (value: string) => {
this._selectedValue = value;
}
render() {
return (
v('div', [
w(ResourceWrapper, {}, [(resource) => {
return w(Select, {
resource: resource({ template, initOptions: { id: this._id, data: [{ value: 'panda'} ] }}),
onValue: this._onValue
})
}]),
v('div', [this._selectedValue])
])
);
}
}
const registry = new Registry();
registerThemeInjector(theme, registry)
const r = renderer(() => w(App, {}));
r.mount({ registry });
SlidePane
Property changes
Added properties
aria?: { [key: string]: string | null }- This property is used to pass custom
aria-*attributes DOM nodes.
- This property is used to pass custom
Removed properties
onOpen?(): void- This property was removed altogether.
- This functionality is no longer supported.
Changes in behavior
The SlidePane no longer supports an onOpen property and instead only uses onRequestClose to update externally-managed open state.
Example of migration from v6 to v7
v6 Example
<SlidePane
open={icache.get('open')}
onOpen={() => icache.set('open', false)}
onRequestClose={() => icache.set('open', false)}
/>
v7 Example
<SlidePane
open={icache.get('open')}
onRequestClose={() => icache.set('open', false)}
/>
Latest example can be found at widgets.dojo.io/#widget/slide-pane/overview
Slider
Property changes
Added properties
initialValue:number- Can be used to provide an initial value or can be used to partially control the slider.
Removed properties
label:string- Removed in favor of a single label handled via a child renderer.
labelAfter:boolean- Removed in favor of a single label handled via a child renderer.
output:() => RenderResultoutputwas moved to a child renderer and should be handled in a child function.
onChange:(value: number) => void- replaced by
onValue(value: number) - since
Slideris now uncontrolled, the newonValueproperty is used to read the slider's value on change, not set it.
- replaced by
onInput:(value: number) => void- removed in favor of controlling input handling internally.
Changes in behavior
Slideris now uncontrolled by default, meaning that parents no longer must manually update the slider's current value in response to user interaction.- The
Slidercan be controlled by using thevalueproperty. - Rendering the label and output is now handled via an optional child renderer of type
RenderResult.
Example of migration from v6 to v7
v6 Example
<Slider
label="How much do you like tribbles?"
min={0}
max={100}
output={(value: number) => {
if (value < 20) {
return 'I am a Klingon';
}
if (value < 40) {
return 'Tribbles only cause trouble';
}
if (value < 60) {
return 'They\`re kind of cute';
}
if (value < 80) {
return 'Most of my salary goes to tribble food';
} else {
return 'I permanently altered the ecology of a planet for my tribbles';
}
}}
step={1}
value={icache.get('tribbleValue')}
onChange={(value) => {
icache.set('tribbleValue', value);
}}
onInput={(value) => {
icache.set('tribbleValue', value);
}}
/>
v7 Example
<Slider
initialValue={0}
min={0}
max={100}
step={1}
>
{{
label: 'How much do you like tribbles?',
output: (value: number) => {
if (value < 20) {
return 'I am a Klingon';
}
if (value < 40) {
return 'Tribbles only cause trouble';
}
if (value < 60) {
return 'They\`re kind of cute';
}
if (value < 80) {
return 'Most of my salary goes to tribble food';
} else {
return 'I permanently altered the ecology of a planet for my tribbles';
}
}
}}
</Slider>
Latest example can be found at widgets.dojo.io/#widget/slider/overview
Snackbar
Property changes
Removed properties
messageRenderer: () => RenderResult- replaced by children.message: RenderResult
actionsRenderer: () => RenderResult- replaced by children.actions: RenderResult
Example of migration from v6 to v7
v6 implementation
<Snackbar
messageRenderer={() => 'Snackbar'}
actionsRenderer={() => 'Actions'} open={true}
/>
v7 implementation
<Snackbar open={true}>
{{
message: 'Snackbar',
actions: 'Actions'
}}
</Snackbar>
Latest example can be found at widgets.dojo.io/#widget/snackbar/overview
Switch
- Split out of
Checkbox, now a separate widget.
Property changes
Removed properties
label:string;- Removed in favor of using a child renderer
onLabel:DNode- Removed in favor of using a child renderer
offLabel:DNode- Removed in favor of using a child renderer
onChange:(value: string, checked: boolean) => void;- replaced by
onValue(checked: boolean)
- replaced by
Example of migration from v6 to v7
v6 Example
<Checkbox
checked={icache.get('checked')}
label="On/Off"
mode={Mode.toggle}
onChange={this.onChange}
/>
v7 Example
<Switch
value={icache.get('checked')}
onValue={(value) => {
icache.set('checked', true);
}}
>
{{ label: 'On/Off' }}
</Switch>
Latest example can be found at widgets.dojo.io/#widget/switch/overview
TabController
Structural changes
<TabController>takes a renderer function as its child instead of a list of<Tab>widgets.- The
<Tab>widget previously used to manage both the tab button and tab content properties has been split into atabsproperty passed to<TabController>and a<TabContent>widget that defines the tab content.
Property changes
Additional Mandatory Properties
tabs: TabItem[];- this prop defines the label and initial state of each tab.
Removed properties
activeIndex: number;- the active tab index is now controlled internally.
- the tab that should be opened by default can be controlled with the new
initialIdproperty that takes the tab'sidrather than its numerical index.
onRequestTabChange: (index: number, key: string) => void;- parents no longer must control which tab is active.
onRequestTabClose: (index: number, key: string) => void;- parents no longer must control which tabs are closed.
Example of migration from v6 to v7
v6 Example
import { tsx, create } from '@dojo/framework/core/vdom';
import icache from '@dojo/framework/core/middleware/icache';
import Set from '@dojo/framework/shim/Set';
import TabController from '@dojo/widgets/tab-controller';
import Tab from '@dojo/widgets/tab';
const factory = create();
export default factory(function Closeable() {
const closed = icache.getOrSet('closed', new Set<string>());
const activeIndex = icache.getOrSet('activeIndex', 2);
return (
<TabController
activeIndex={activeIndex}
onRequestTabClose={(index, key) => {
icache.set('closed', new Set([...closed, key]));
}}
onRequestTabChange={(index, key) => {
icache.set('activeIndex', index);
}}
>
{!closed.has('tab0') && (
<Tab key="tab0" closeable={true} label="Tab One">
Hello Tab One
</Tab>
)}
<Tab key="tab1" disabled={true} label="Tab Two">
Hello Tab Two
</Tab>
<Tab key="tab2" label="Tab Three">
Hello Tab Three
</Tab>
<Tab key="tab3" label="Tab Four">
Hello Tab Four
</Tab>
</TabController>
);
});
v7 Example
import { tsx, create } from '@dojo/framework/core/vdom';
import TabController, { TabItem } from '@dojo/widgets/tab-controller';
import TabContent from '@dojo/widgets/tab-controller/TabContent';
const factory = create();
export default factory(function Closeable() {
const tabs = [
{ closeable: true, id: 'tab0', label: 'Tab One' },
{ disabled: true, id: 'tab1', label: 'Tab Two' },
{ id: 'tab2', label: 'Tab Three' },
{ id: 'tab3', label: 'Tab Four' }
];
return (
<TabController initialId="tab2" tabs={tabs}>
{(
tabs: TabItem[],
isActive: (id: string) => boolean,
isClosed: (id: string) => boolean
) => [
<TabContent key="tab0" active={isActive('tab0')} closed={isClosed('tab0')}>
Hello Tab One
</TabContent>,
<TabContent key="tab1" active={isActive('tab1')} closed={isClosed('tab1')}>
Hello Tab Two
</TabContent>,
<TabContent key="tab2" active={isActive('tab2')} closed={isClosed('tab2')}>
Hello Tab Three
</TabContent>,
<TabContent key="tab3" active={isActive('tab3')} closed={isClosed('tab3')}>
Hello Tab Four
</TabContent>
]}
</TabController>
);
});
Latest example can be found at widgets.dojo.io/#widget/tab-controller/overview
TextArea
Property changes
Added properties
initialValue?: string;- Can be used to provide an initial value or can be used to partially control the text area.
Removed properties
label:string;<TextArea>now takes an optional child that will be rendered as its label.
Changes in behavior
TextAreais now uncontrolled by default, meaning parent widgets are no longer responsible for updating the current value in response to changes or events. The widget is controllable withvalue.
Example of migration from v6 to v7
v6 example
<TextArea label="Textarea with label" />
v7 example
<TextArea>Textarea with label</TextArea>
Latest example can be found at widgets.dojo.io/#widget/text-area/overview
TextInput
Property changes
Added properties
initialValue?: T['value'];- Can be used to provide an initial value or can be used to partially control the text input.
Removed properties
label:string- Specifying a label is now done with a
labelkey on a child renderer object (see the example below)
- Specifying a label is now done with a
leading:() => DNode- Specifying leading content is now done with a
leadingkey on a child renderer object (see the example below) - Since the original property function receives no arguments, the child renderer object expects a static value instead of a function.
- Specifying leading content is now done with a
trailing:() => DNode- Specifying trailing content is now done with a
trailingkey on a child renderer object (see the example below) - Since the original property function receives no arguments, the child renderer object expects a static value instead of a function.
- Specifying trailing content is now done with a
Changes in behavior
TextInputis now uncontrolled by default, meaning parent widgets are no longer responsible for updating the current value in response to changes or events. The widget is controllable withvalue.Addonwidget is now exported fromTextInputwhich can be used to wrap theleading/trailingsections.
Example of migration from v6 to v7
v6 example
<TextInput
type="text"
label="Input Label"
value="Initial value"
leading={() => <span>A</span>}
trailing={() => <span>Z</span>}
/>
v7 example
<TextInput type="text" value="Initial value">
{{
label: 'Input Label',
leading: <Addon>A</Addon>,
trailing: <Addon filled>Z</Addon>
}}
</TextInput>
Latest example can be found at widgets.dojo.io/#widget/text-input/overview
TimePicker
Property changes
Additional Properties
format?: '24' | '12';- Specifies whether or not the time is displayed in 24h or 12h format
onValidate?(valid: boolean, message: string): void;- Called when validation occurs on the time picker.
initialValue?: string;- Used to set the initial value of the time picker.
- The time picker is now internally managed by default and does not need to be managed by the parent widget, but can still be controlled using
valueandonValue.
Changed properties
start- Renamed to
minto match with native time picker
- Renamed to
end- Renamed to
maxto match with native time picker
- Renamed to
isOptionDisabled- Renamed to
timeDisabled - Takes a function with a single
Dateparameter. The option is disabled if the function returns falsey
- Renamed to
label- Replaced with child renderer
Removed properties
widgetId- No longer needed
valid- Validation is now handled internally by the time picker and exposed via the
onValidateproperty
- Validation is now handled internally by the time picker and exposed via the
useNativeElement- No longer supported
readOnly- No longer supported. Time picker can be
disabledif required
- No longer supported. Time picker can be
options- It is no longer necessary to manually specify the options. The options may be configured via the
start,end, andstepproperties.
- It is no longer necessary to manually specify the options. The options may be configured via the
openOnFocus- No longer supported. Clicking the button or using the enter/down arrow is required to open the time picker menu
onRequestOptions- No longer supported
onOver- No longer supported
onOut- No longer supported
onMenuChange- No longer supported
onFocus- No longer supported
onClick- No longer supported
onBlur- No longer supported
labelHidden- No longer supported
labelAfter- No longer supported
inputProperties- No longer supported
clearable- No longer supported, the time picker is not clearable
autoBlur- No longer supported
Changes in behavior
The time picker will generate its own time options manually now, and therefore does not require the parent widget to pass in a list of time options.
Example of migration from v6 to v7
v6 Example
<TimePicker
start="12:00:00"
end="12:00:59"
step={1}
onValue={(value) => icache.set('value', value)}
label="Time: "
/>
v7 Example
<TimePicker min="12:00:00" max="12:00:59" step={1} onValue={(value) => icache.set('value', value)}>
{{ label: 'Time: ' }}
</TimePicker>
Latest example can be found at widgets.dojo.io/#widget/time-picker/overview
TitlePane
Property changes
Changed properties
onClose?(): void- This property replaces
onRequestClose. - This property receives no arguments.
- This property replaces
onOpen?(): void- This property replaces
onRequestOpen. - This property receives no arguments.
- This property replaces
initialOpen?: boolean- This property sets initial open state.
- This widget then manages its open state internally.
- The
openproperty can alternatively be used for full control.
children: TitlePaneChildren- This property no longer accepts
DNodecontent. - This property accepts a child renderer object.
- Pane title and content are set using this renderer.
- This property no longer accepts
Removed properties
title: DNode- This property was removed altogether.
- Pane titles are now set using a child renderer.
Changes in behavior
The TitlePane widget is now uncontrolled by default, meaning it manages its own open state internally. An initialOpen property can be used to set initial open state, and onOpen and onClose properties can be used to detect when this open state changes. If full-control is needed to support complex use-cases - such as restrictions around opening or closing - the open property can be used instead of initialOpen to mandate open state.
The TitlePane now uses a child renderer object to determine its title and content. This means that an object is passed as the widget's only child with keys for title and content, each of which return elements to render accordingly.
Example of migration from v6 to v7
v6 Example
<TitlePane
title="Title"
onRequestClose={() => icache.set('open', false)}
onRequestOpen={() => icache.set('open', true)}
open={icache.get('open')}
>
Content
</TitlePane>
v7 Example
<TitlePane>
{{
title: 'Title',
content: 'Content'
}}
</TitlePane>
Latest example can be found at widgets.dojo.io/#widget/title-pane/overview
Tooltip
Property changes
Changed properties
children:DNode- This property no longer accepts
DNodetriggers. - This property accepts a child renderer object.
- The trigger and contents are set using this renderer.
- This property no longer accepts
Removed properties
content:DNode- The tooltip content is now set via a child renderer object.
Changes in behavior
- Both the tooltip trigger and content are specified on a child renderer object rather than as a child
DNodeand property, respectively.
Example of migration from v6 to v7
v6 Example
<Tooltip content="This tooltip shows on click" open={icache.get('show')}>
<button
onclick={() => {
icache.set('show', !icache.get('show'));
}}
>
Toggle Tooltip
</button>
</Tooltip>
v7 Example
<Tooltip open={icache.get('show')}>
{{
content: 'This tooltip shows on click',
trigger: (
<button
onclick={() => {
icache.set('show', !icache.get('show'));
}}
>
Toggle Tooltip
</button>
)
}}
</Tooltip>
Latest example can be found at widgets.dojo.io/#widget/tooltip/overview