-
Notifications
You must be signed in to change notification settings - Fork 11
Expand file tree
/
Copy pathRadioInput.ts
More file actions
118 lines (104 loc) · 3.48 KB
/
Copy pathRadioInput.ts
File metadata and controls
118 lines (104 loc) · 3.48 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
/*
* This file belongs to Hoist, an application development toolkit
* developed by Extremely Heavy Industries (www.xh.io | info@xh.io)
*
* Copyright © 2026 Extremely Heavy Industries Inc.
*/
import {HoistInputModel, HoistInputProps, useHoistInputModel} from '@xh/hoist/cmp/input';
import {hoistCmp, HoistProps, HSide} from '@xh/hoist/core';
import '@xh/hoist/desktop/register';
import {radio, radioGroup} from '@xh/hoist/kit/blueprint';
import {computed, makeObservable} from '@xh/hoist/mobx';
import {getTestId, TEST_ID, withDefault} from '@xh/hoist/utils/js';
import {filter, isObject} from 'lodash';
import './RadioInput.scss';
export interface RadioInputProps extends HoistProps, HoistInputProps {
/** True to display each radio button inline with each other. */
inline?: boolean;
/** Placement of each option's label relative its radio button, default 'right'. */
labelSide?: HSide;
/** Array of available options */
options: (RadioOption | any)[];
}
export interface RadioOption {
value: any;
label?: string;
disabled?: boolean;
}
/**
* An input for managing Radio Buttons.
*/
export const [RadioInput, radioInput] = hoistCmp.withFactory<RadioInputProps>({
displayName: 'RadioInput',
className: 'xh-radio-input',
render(props, ref) {
return useHoistInputModel(cmp, props, ref, RadioInputModel);
}
});
//-----------------------
// Implementation
//-----------------------
class RadioInputModel extends HoistInputModel {
override xhImpl = true;
get enabledInputs(): HTMLInputElement[] {
const btns = this.domEl?.querySelectorAll('input') ?? [];
return filter(btns, {disabled: false});
}
@computed
get normalizedOptions(): RadioOption[] {
const options = this.componentProps.options ?? [];
return options.map(o => {
if (isObject(o)) {
const {label, value, disabled} = o as RadioOption;
return {value: this.toInternal(value), label, disabled};
} else {
return {value: this.toInternal(o), label: o.toString()};
}
});
}
constructor() {
super();
makeObservable(this);
}
//-------------------------
// Options / value handling
//-------------------------
onChange = e => {
this.noteValueChange(e.target.value);
};
//-----------------
// Overrides
//-----------------
override blur() {
this.enabledInputs.forEach(it => it.blur());
}
override focus() {
this.enabledInputs[0]?.focus();
}
}
// Note: we don't use the `ref` here, but the presence of a second argument is required.
const cmp = hoistCmp.factory<RadioInputModel>(({model, className, ...props}, ref) => {
const {normalizedOptions} = model,
labelSide = withDefault(props.labelSide, 'right');
const items = normalizedOptions.map(opt => {
return radio({
alignIndicator: labelSide === 'left' ? 'right' : 'left',
disabled: opt.disabled,
label: opt.label,
value: opt.value,
className: 'xh-radio-input-option',
[TEST_ID]: getTestId(props.testId, `${opt.value}`),
onFocus: model.onFocus,
onBlur: model.onBlur
});
});
return radioGroup({
className,
items,
disabled: props.disabled,
inline: props.inline,
selectedValue: model.renderValue,
onChange: model.onChange,
[TEST_ID]: props.testId
});
});