Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[ISSUE-677] Helpertext on combobox #723

Merged
merged 8 commits into from
Jun 10, 2019
Merged
Show file tree
Hide file tree
Changes from 6 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 11 additions & 4 deletions src/combobox/example/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -65,7 +65,10 @@ export default class App extends WidgetBase {
private _value7 = '';
private _value8 = '';
private _value9 = '';
private _invalid = false;
private _valid: { valid: boolean | undefined; message: string } = {
valid: true,
message: 'Please enter value of state'
};

onChange(value: string, key?: string) {
if (!key) {
Expand All @@ -89,7 +92,6 @@ export default class App extends WidgetBase {

render(): DNode {
const { onChange, onRequestResults } = this;

return v(
'div',
{
Expand Down Expand Up @@ -180,16 +182,21 @@ export default class App extends WidgetBase {
required: true,
onChange: (value: string) => {
this._value9 = value;
this._invalid = value.trim().length === 0;
this._valid.valid = value.trim().length !== 0;
this.invalidate();
},
getResultLabel: (result: any) => result.value,
onRequestResults,
results: this._results,
value: this._value9,
invalid: this._invalid,
valid: this._valid,
helperText: 'helper text',
inputProperties: {
placeholder: 'Enter a value'
},
onValidate: (valid: boolean | undefined) => {
this._valid.valid = valid;
this.invalidate();
}
})
]
Expand Down
78 changes: 54 additions & 24 deletions src/combobox/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ import { customElement } from '@dojo/framework/widget-core/decorators/customElem
* @property getResultLabel Can be used to get the text label of a result based on the underlying result object
* @property getResultSelected Can be used to highlight the selected result. Defaults to checking the result label
* @property getResultValue Can be used to define a value returned by onChange when a given result is selected. Defaults to getResultLabel
* @property helpertext Displays text at bottom of widget
* @property widgetId Optional id string for the combobox, set on the text input
* @property inputProperties TextInput properties to set on the underlying input
* @property invalid Determines if this input is valid
Expand All @@ -54,16 +55,18 @@ export interface ComboBoxProperties extends ThemedProperties, LabeledProperties,
getResultLabel?(result: any): DNode;
getResultSelected?(result: any): boolean;
getResultValue?(result: any): string;
helperText?: string;
widgetId?: string;
inputProperties?: TextInputProperties;
invalid?: boolean;
valid?: { valid?: boolean; message?: string } | boolean;
isResultDisabled?(result: any): boolean;
onBlur?(value: string, key?: string | number): void;
onChange?(value: string, key?: string | number): void;
onFocus?(value: string, key?: string | number): void;
onMenuChange?(open: boolean, key?: string | number): void;
onRequestResults?(key?: string | number): void;
onResultSelect?(result: any, key?: string | number): void;
onValidate?: (valid: boolean | undefined, message: string) => void;
openOnFocus?: boolean;
readOnly?: boolean;
required?: boolean;
Expand All @@ -85,22 +88,29 @@ export enum Operation {
'theme',
'classes',
'extraClasses',
'labelAfter',
'labelHidden',
'clearable',
'disabled',
'inputProperties',
'invalid',
'valid',
'isResultDisabled',
'labelAfter',
'helperText',
'labelHidden',
'openOnFocus',
'readOnly',
'required',
'results'
],
attributes: ['widgetId', 'label', 'value'],
events: ['onBlur', 'onChange', 'onFocus', 'onMenuChange', 'onRequestResults', 'onResultSelect']
events: [
'onBlur',
'onChange',
'onFocus',
'onMenuChange',
'onRequestResults',
'onResultSelect',
'onValidate'
]
})
export class ComboBox extends I18nMixin(ThemedMixin(FocusMixin(WidgetBase)))<ComboBoxProperties> {
private _activeIndex = 0;
Expand Down Expand Up @@ -289,18 +299,17 @@ export class ComboBox extends I18nMixin(ThemedMixin(FocusMixin(WidgetBase)))<Com
this.invalidate();
}

protected getRootClasses(): (string | null)[] {
const { clearable, invalid } = this.properties;
const focus = this.meta(Focus).get('root');
protected get validity() {
const { valid = { valid: undefined, message: undefined } } = this.properties;

return [
css.root,
this._open ? css.open : null,
clearable ? css.clearable : null,
focus.containsFocus ? css.focused : null,
invalid === true ? css.invalid : null,
invalid === false ? css.valid : null
];
if (typeof valid === 'boolean') {
return { valid, message: undefined };
}

return {
valid: valid.valid,
message: valid.message
};
}

protected renderInput(results: any[]): DNode {
Expand All @@ -309,13 +318,16 @@ export class ComboBox extends I18nMixin(ThemedMixin(FocusMixin(WidgetBase)))<Com
disabled,
widgetId = this._idBase,
inputProperties = {},
invalid,
readOnly,
required,
value = '',
theme
theme,
helperText,
onValidate
} = this.properties;

const { valid, message } = this.validity;

return w(TextInput, {
...inputProperties,
key: 'textinput',
Expand All @@ -326,14 +338,16 @@ export class ComboBox extends I18nMixin(ThemedMixin(FocusMixin(WidgetBase)))<Com
: null,
autocomplete: 'list'
},
valid: typeof invalid === 'boolean' ? !invalid : undefined,
valid: { valid, message: this._open ? undefined : message },
disabled,
widgetId,
helperText: this._open ? undefined : helperText,
focus: this.shouldFocus,
onBlur: this._onInputBlur,
onFocus: this._onInputFocus,
onInput: this._onInput,
onKeyDown: this._onInputKeyDown,
onValidate,
readOnly,
required,
theme,
Expand Down Expand Up @@ -428,22 +442,38 @@ export class ComboBox extends I18nMixin(ThemedMixin(FocusMixin(WidgetBase)))<Com
const {
clearable = false,
widgetId = this._idBase,
invalid,
label,
readOnly,
required,
disabled,
labelHidden,
labelAfter,
results = [],
theme,
classes
} = this.properties;

const { valid } = this.validity;

const { messages } = this.localizeBundle(commonBundle);
const focus = this.meta(Focus).get('root');

const menu = this.renderMenu(results);
this._onMenuChange();

if (results.length === 0 && this._open === true) {
this._open = false;
this.invalidate();
}

const rootClasses = [
css.root,
this._open ? css.open : null,
clearable ? css.clearable : null,
focus.containsFocus ? css.focused : null,
valid === false ? css.invalid : null,
valid === true ? css.valid : null
];

this._wasOpen = this._open;

const controls = [
Expand All @@ -456,7 +486,7 @@ export class ComboBox extends I18nMixin(ThemedMixin(FocusMixin(WidgetBase)))<Com
classes,
disabled,
focused: focus.containsFocus,
invalid,
invalid: !valid,
readOnly,
required,
hidden: labelHidden,
Expand Down Expand Up @@ -486,10 +516,10 @@ export class ComboBox extends I18nMixin(ThemedMixin(FocusMixin(WidgetBase)))<Com
return v(
'div',
{
classes: this.theme(this.getRootClasses()),
classes: this.theme(rootClasses),
key: 'root'
},
labelAfter ? controls.reverse() : controls
controls
);
}
}
Expand Down
Loading