@rivtn/noseur 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +2 -0
- package/dist/esm/Template.d.ts +7 -0
- package/dist/esm/Template.js +13 -0
- package/dist/esm/compose/Composed.css +437 -0
- package/dist/esm/compose/exotic/ColorPicker.d.ts +41 -0
- package/dist/esm/compose/exotic/ColorPicker.js +85 -0
- package/dist/esm/compose/exotic/ColorSlider.d.ts +30 -0
- package/dist/esm/compose/exotic/ColorSlider.js +99 -0
- package/dist/esm/compose/form/ComposedPassword.d.ts +25 -0
- package/dist/esm/compose/form/ComposedPassword.js +103 -0
- package/dist/esm/compose/form/DateTimeInput.d.ts +28 -0
- package/dist/esm/compose/form/DateTimeInput.js +154 -0
- package/dist/esm/compose/form/DateTimePicker.d.ts +341 -0
- package/dist/esm/compose/form/DateTimePicker.js +1265 -0
- package/dist/esm/compose/form/FormControl.d.ts +33 -0
- package/dist/esm/compose/form/FormControl.js +163 -0
- package/dist/esm/compose/form/FormGroup.d.ts +14 -0
- package/dist/esm/compose/form/FormGroup.js +58 -0
- package/dist/esm/compose/overlay/Alert.d.ts +56 -0
- package/dist/esm/compose/overlay/Alert.js +267 -0
- package/dist/esm/constants/Alignment.d.ts +17 -0
- package/dist/esm/constants/Alignment.js +18 -0
- package/dist/esm/constants/Direction.d.ts +26 -0
- package/dist/esm/constants/Direction.js +22 -0
- package/dist/esm/constants/Orientation.d.ts +8 -0
- package/dist/esm/constants/Orientation.js +9 -0
- package/dist/esm/constants/Scheme.d.ts +39 -0
- package/dist/esm/constants/Scheme.js +43 -0
- package/dist/esm/constants/Transition.d.ts +81 -0
- package/dist/esm/constants/Transition.js +85 -0
- package/dist/esm/constants/Types.d.ts +74 -0
- package/dist/esm/constants/Types.js +14 -0
- package/dist/esm/core/ComponentBaseProps.d.ts +53 -0
- package/dist/esm/core/ComponentBaseProps.js +33 -0
- package/dist/esm/core/noseur.css +2390 -0
- package/dist/esm/data/Column.d.ts +235 -0
- package/dist/esm/data/Column.js +98 -0
- package/dist/esm/data/Data.css +213 -0
- package/dist/esm/data/Data.d.ts +98 -0
- package/dist/esm/data/Data.js +142 -0
- package/dist/esm/data/List.d.ts +14 -0
- package/dist/esm/data/List.js +117 -0
- package/dist/esm/data/Table.d.ts +22 -0
- package/dist/esm/data/Table.js +236 -0
- package/dist/esm/form/Button.d.ts +35 -0
- package/dist/esm/form/Button.js +131 -0
- package/dist/esm/form/Calendar.d.ts +20 -0
- package/dist/esm/form/Calendar.js +46 -0
- package/dist/esm/form/Checkbox.d.ts +20 -0
- package/dist/esm/form/Checkbox.js +155 -0
- package/dist/esm/form/ColorMap.d.ts +22 -0
- package/dist/esm/form/ColorMap.js +43 -0
- package/dist/esm/form/ColorPalette.d.ts +28 -0
- package/dist/esm/form/ColorPalette.js +87 -0
- package/dist/esm/form/Dropdown.d.ts +78 -0
- package/dist/esm/form/Dropdown.js +360 -0
- package/dist/esm/form/FileInput.d.ts +134 -0
- package/dist/esm/form/FileInput.js +523 -0
- package/dist/esm/form/Form.css +467 -0
- package/dist/esm/form/Input.d.ts +45 -0
- package/dist/esm/form/Input.js +186 -0
- package/dist/esm/form/RadioButton.d.ts +21 -0
- package/dist/esm/form/RadioButton.js +178 -0
- package/dist/esm/form/Slider.d.ts +21 -0
- package/dist/esm/form/Slider.js +163 -0
- package/dist/esm/hooks/useSearchParams.d.ts +15 -0
- package/dist/esm/hooks/useSearchParams.js +50 -0
- package/dist/esm/hooks/useSubscription.d.ts +9 -0
- package/dist/esm/hooks/useSubscription.js +26 -0
- package/dist/esm/index.d.ts +60 -0
- package/dist/esm/index.js +73 -0
- package/dist/esm/layout/GridView.d.ts +23 -0
- package/dist/esm/layout/GridView.js +34 -0
- package/dist/esm/layout/Layout.css +5 -0
- package/dist/esm/misc/Misc.css +164 -0
- package/dist/esm/misc/ProgressBar.d.ts +22 -0
- package/dist/esm/misc/ProgressBar.js +86 -0
- package/dist/esm/overlay/Dialog.d.ts +46 -0
- package/dist/esm/overlay/Dialog.js +290 -0
- package/dist/esm/overlay/Message.d.ts +35 -0
- package/dist/esm/overlay/Message.js +187 -0
- package/dist/esm/overlay/Overlay.css +382 -0
- package/dist/esm/overlay/Popover.d.ts +30 -0
- package/dist/esm/overlay/Popover.js +245 -0
- package/dist/esm/overlay/Portal.d.ts +11 -0
- package/dist/esm/overlay/Portal.js +29 -0
- package/dist/esm/overlay/Toast.d.ts +49 -0
- package/dist/esm/overlay/Toast.js +341 -0
- package/dist/esm/panel/Accordion.d.ts +26 -0
- package/dist/esm/panel/Accordion.js +127 -0
- package/dist/esm/panel/Panel.css +317 -0
- package/dist/esm/panel/Panel.d.ts +43 -0
- package/dist/esm/panel/Panel.js +125 -0
- package/dist/esm/panel/ScrollPanel.d.ts +27 -0
- package/dist/esm/panel/ScrollPanel.js +43 -0
- package/dist/esm/panel/TabPane.d.ts +82 -0
- package/dist/esm/panel/TabPane.js +237 -0
- package/dist/esm/presentation/Chart.d.ts +49 -0
- package/dist/esm/presentation/Chart.js +62 -0
- package/dist/esm/presentation/Paginator.d.ts +90 -0
- package/dist/esm/presentation/Paginator.js +331 -0
- package/dist/esm/presentation/Presentation.css +23 -0
- package/dist/esm/sensor/DragSensor.d.ts +50 -0
- package/dist/esm/sensor/DragSensor.js +156 -0
- package/dist/esm/sensor/ViewportSensor.d.ts +18 -0
- package/dist/esm/sensor/ViewportSensor.js +85 -0
- package/dist/esm/utils/BoolHelper.d.ts +13 -0
- package/dist/esm/utils/BoolHelper.js +105 -0
- package/dist/esm/utils/Classname.d.ts +9 -0
- package/dist/esm/utils/Classname.js +20 -0
- package/dist/esm/utils/ColorHelper.d.ts +127 -0
- package/dist/esm/utils/ColorHelper.js +198 -0
- package/dist/esm/utils/DOMUtils.d.ts +142 -0
- package/dist/esm/utils/DOMUtils.js +759 -0
- package/dist/esm/utils/DateHelper.d.ts +115 -0
- package/dist/esm/utils/DateHelper.js +338 -0
- package/dist/esm/utils/Debugger.d.ts +12 -0
- package/dist/esm/utils/Debugger.js +30 -0
- package/dist/esm/utils/FileHelper.d.ts +8 -0
- package/dist/esm/utils/FileHelper.js +65 -0
- package/dist/esm/utils/FunctionStackManager.d.ts +13 -0
- package/dist/esm/utils/FunctionStackManager.js +59 -0
- package/dist/esm/utils/InputHelper.d.ts +37 -0
- package/dist/esm/utils/InputHelper.js +70 -0
- package/dist/esm/utils/MicroBuilder.d.ts +24 -0
- package/dist/esm/utils/MicroBuilder.js +61 -0
- package/dist/esm/utils/ObjectHelper.d.ts +51 -0
- package/dist/esm/utils/ObjectHelper.js +334 -0
- package/dist/esm/utils/StringHelper.d.ts +10 -0
- package/dist/esm/utils/StringHelper.js +54 -0
- package/dist/esm/utils/Subscriber.d.ts +14 -0
- package/dist/esm/utils/Subscriber.js +27 -0
- package/dist/esm/utils/Timer.d.ts +32 -0
- package/dist/esm/utils/Timer.js +68 -0
- package/dist/esm/utils/TypeChecker.d.ts +12 -0
- package/dist/esm/utils/TypeChecker.js +38 -0
- package/package.json +63 -0
|
@@ -0,0 +1,360 @@
|
|
|
1
|
+
import "./Form.css";
|
|
2
|
+
import React from 'react';
|
|
3
|
+
import { Scheme } from "../constants/Scheme";
|
|
4
|
+
import { DOMHelper } from "../utils/DOMUtils";
|
|
5
|
+
import { Classname } from "../utils/Classname";
|
|
6
|
+
import { BoolHelper } from "../utils/BoolHelper";
|
|
7
|
+
import { TypeChecker } from "../utils/TypeChecker";
|
|
8
|
+
import { ObjectHelper } from "../utils/ObjectHelper";
|
|
9
|
+
import { Popover } from "../overlay/Popover";
|
|
10
|
+
import { Position } from "../constants/Alignment";
|
|
11
|
+
import { FunctionStackManager } from "../utils/FunctionStackManager";
|
|
12
|
+
import { FormControl } from "../compose/form/FormControl";
|
|
13
|
+
import { TextInput } from "./Input";
|
|
14
|
+
// TODO implements keyboard and mouse shortcuts
|
|
15
|
+
class DropdownComponent extends React.Component {
|
|
16
|
+
static defaultProps = {
|
|
17
|
+
disabled: false,
|
|
18
|
+
highlight: false,
|
|
19
|
+
popoverProps: {},
|
|
20
|
+
borderless: false,
|
|
21
|
+
textInputProps: {},
|
|
22
|
+
formControlProps: {},
|
|
23
|
+
responsiveWidth: true,
|
|
24
|
+
selectedOptionIndex: -1,
|
|
25
|
+
scheme: Scheme.SECONDARY,
|
|
26
|
+
iconPosition: Position.LEFT,
|
|
27
|
+
togglePosition: Position.RIGHT,
|
|
28
|
+
optionGroupChildrenKey: "items",
|
|
29
|
+
toggleIcons: {
|
|
30
|
+
hide: 'fa fa-angle-up',
|
|
31
|
+
show: 'fa fa-angle-down',
|
|
32
|
+
},
|
|
33
|
+
};
|
|
34
|
+
state = {
|
|
35
|
+
popoverVisible: false,
|
|
36
|
+
options: this.props.options,
|
|
37
|
+
selectedOptionIndex: this.props.selectedOptionIndexes || { primaryIndex: this.props.selectedOptionIndex, secondaryIndex: this.props.selectedOptionIndex },
|
|
38
|
+
};
|
|
39
|
+
optionTemplate;
|
|
40
|
+
compoundElement;
|
|
41
|
+
optionGroupTemplate;
|
|
42
|
+
internalPopoverElement;
|
|
43
|
+
internalTextInputElement;
|
|
44
|
+
internalManageRefCache;
|
|
45
|
+
functionStackManager = new FunctionStackManager();
|
|
46
|
+
constructor(props) {
|
|
47
|
+
super(props);
|
|
48
|
+
this.optionTemplate = this.props.optionTemplate ?? this.buildSingleOption;
|
|
49
|
+
this.optionGroupTemplate = this.props.optionGroupTemplate ?? this.buildSingleOption;
|
|
50
|
+
this.togglePopover = this.togglePopover.bind(this);
|
|
51
|
+
this.onDropdownShow = this.onDropdownShow.bind(this);
|
|
52
|
+
this.onDropdownHide = this.onDropdownHide.bind(this);
|
|
53
|
+
}
|
|
54
|
+
componentDidMount() {
|
|
55
|
+
this.internalManageRefCache = {
|
|
56
|
+
toggle: this.togglePopover,
|
|
57
|
+
changeOptions: (options) => {
|
|
58
|
+
this.setState({ options });
|
|
59
|
+
},
|
|
60
|
+
hideDropDown: (e) => { if (this.state.popoverVisible) {
|
|
61
|
+
this.togglePopover(e, true);
|
|
62
|
+
} },
|
|
63
|
+
showDropDown: (e) => { if (!this.state.popoverVisible) {
|
|
64
|
+
this.togglePopover(e, true);
|
|
65
|
+
} },
|
|
66
|
+
};
|
|
67
|
+
ObjectHelper.resolveManageRef(this, this.internalManageRefCache);
|
|
68
|
+
}
|
|
69
|
+
componentDidUpdate(prevProps, _) {
|
|
70
|
+
const optionsChanged = !BoolHelper.deepEqual(this.props, prevProps, ["options"]);
|
|
71
|
+
const selectedOptionIndexChanged = !BoolHelper.deepEqual(this.props, prevProps, ["selectedOptionIndex"]);
|
|
72
|
+
if (optionsChanged || selectedOptionIndexChanged) {
|
|
73
|
+
let options = this.state.options;
|
|
74
|
+
if (optionsChanged)
|
|
75
|
+
options = this.props.options;
|
|
76
|
+
const newState = { options };
|
|
77
|
+
if (selectedOptionIndexChanged) {
|
|
78
|
+
const selectedOptionIndex = this.props.selectedOptionIndexes
|
|
79
|
+
?? { primaryIndex: this.props.selectedOptionIndex, secondaryIndex: this.props.selectedOptionIndex };
|
|
80
|
+
if (selectedOptionIndex.primaryIndex === -1) {
|
|
81
|
+
if (this.props.renderOptionAsPlaceholder)
|
|
82
|
+
this.internalTextInputElement.placeholder = this.props.placeholder;
|
|
83
|
+
else
|
|
84
|
+
this.internalTextInputElement.value = "";
|
|
85
|
+
}
|
|
86
|
+
else {
|
|
87
|
+
newState.selectedOptionIndex = selectedOptionIndex;
|
|
88
|
+
if (optionsChanged || this.props.forceUpdateIfSelectedIndexChanges) {
|
|
89
|
+
this.selectOption(null, newState.selectedOptionIndex, newState.options.find((_, i) => i === selectedOptionIndex.primaryIndex), true);
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
this.setState(newState);
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
componentWillUnmount() {
|
|
97
|
+
ObjectHelper.resolveManageRef(this, null);
|
|
98
|
+
}
|
|
99
|
+
togglePopover(e, ignoreEditable = true) {
|
|
100
|
+
e.stopPropagation();
|
|
101
|
+
if (!this.internalPopoverElement || (!ignoreEditable && this.props.editable && e.target === this.internalTextInputElement))
|
|
102
|
+
return;
|
|
103
|
+
this.internalPopoverElement.toggle(e, this.compoundElement);
|
|
104
|
+
}
|
|
105
|
+
onDropdownHide() {
|
|
106
|
+
this.setState({ popoverVisible: false });
|
|
107
|
+
if (this.props.onDropdownHide)
|
|
108
|
+
this.props.onDropdownHide();
|
|
109
|
+
}
|
|
110
|
+
onDropdownShow() {
|
|
111
|
+
this.setState({ popoverVisible: true });
|
|
112
|
+
if (this.props.onDropdownShow)
|
|
113
|
+
this.props.onDropdownShow();
|
|
114
|
+
}
|
|
115
|
+
selectOption(e, selectedOptionIndex, option, skipReport) {
|
|
116
|
+
if (!skipReport && selectedOptionIndex.primaryIndex === -1) {
|
|
117
|
+
if (this.props.onDeSelectOption)
|
|
118
|
+
this.props.onDeSelectOption(e);
|
|
119
|
+
}
|
|
120
|
+
;
|
|
121
|
+
if (selectedOptionIndex.primaryIndex === -1 || (skipReport || !this.props.onSelectOption || this.props.onSelectOption(option, e) !== true)) {
|
|
122
|
+
if (!skipReport)
|
|
123
|
+
this.setState({ selectedOptionIndex: selectedOptionIndex });
|
|
124
|
+
const optionLabel = option ? this.resolveOptionLabel(option) : (this.props.renderOptionAsPlaceholder ? this.props.placeholder : "");
|
|
125
|
+
if (this.props.renderOptionAsPlaceholder) {
|
|
126
|
+
this.internalTextInputElement.placeholder = optionLabel;
|
|
127
|
+
}
|
|
128
|
+
else {
|
|
129
|
+
this.internalTextInputElement.value = optionLabel;
|
|
130
|
+
}
|
|
131
|
+
if (!this.props.fill && this.props.responsiveWidth) {
|
|
132
|
+
const sidePaddings = parseInt(DOMHelper.getElementStyle(this.internalTextInputElement).paddingLeft) + parseInt(DOMHelper.getElementStyle(this.internalTextInputElement).paddingRight);
|
|
133
|
+
this.internalTextInputElement.style.width = `${DOMHelper.getTextWidth(optionLabel, this.internalTextInputElement) + sidePaddings}px`;
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
if (skipReport)
|
|
137
|
+
return;
|
|
138
|
+
return this.togglePopover(e, false);
|
|
139
|
+
}
|
|
140
|
+
resolveOptionLabel(option) {
|
|
141
|
+
if (!option)
|
|
142
|
+
return;
|
|
143
|
+
const optionMap = this.props.optionMap;
|
|
144
|
+
if (!optionMap || !optionMap.label)
|
|
145
|
+
return option.label ? option.label : "";
|
|
146
|
+
if (optionMap.label.indexOf('{') < 0) {
|
|
147
|
+
return option[optionMap.label] || optionMap.label;
|
|
148
|
+
}
|
|
149
|
+
return ObjectHelper.expandStringTemplate(optionMap.label, option);
|
|
150
|
+
}
|
|
151
|
+
resolveOptionIcon(option) {
|
|
152
|
+
if (!option || this.props.noIcon)
|
|
153
|
+
return null;
|
|
154
|
+
const optionMap = this.props.optionMap;
|
|
155
|
+
let icon = option.icon;
|
|
156
|
+
if (optionMap && optionMap.icon) {
|
|
157
|
+
if (optionMap.icon.indexOf && optionMap.icon.indexOf('{') >= 0) {
|
|
158
|
+
icon = ObjectHelper.expandStringTemplate(optionMap.icon, option);
|
|
159
|
+
}
|
|
160
|
+
else {
|
|
161
|
+
icon = option[optionMap.icon];
|
|
162
|
+
}
|
|
163
|
+
}
|
|
164
|
+
return option ? (TypeChecker.isString(icon) ? React.createElement("img", { src: icon }) : icon) : null;
|
|
165
|
+
}
|
|
166
|
+
buildSingleOption(option) {
|
|
167
|
+
const icon = this.resolveOptionIcon(option);
|
|
168
|
+
const label = this.resolveOptionLabel(option);
|
|
169
|
+
return (React.createElement("span", { className: "noseur-dropdown-popover-li-item" },
|
|
170
|
+
icon,
|
|
171
|
+
label));
|
|
172
|
+
}
|
|
173
|
+
getSelectedOption() {
|
|
174
|
+
if (!this.state.options || this.state.selectedOptionIndex == null || this.state.selectedOptionIndex.primaryIndex == null ||
|
|
175
|
+
this.state.selectedOptionIndex.primaryIndex < 0 || this.state.selectedOptionIndex.primaryIndex >= Object.keys(this.state.options).length) {
|
|
176
|
+
return null;
|
|
177
|
+
}
|
|
178
|
+
const childrenKey = this.props.optionGroupChildrenKey;
|
|
179
|
+
const selectedOption = this.state.options[this.state.selectedOptionIndex.primaryIndex];
|
|
180
|
+
return (TypeChecker.isArray(selectedOption) && childrenKey in selectedOption)
|
|
181
|
+
? selectedOption[childrenKey][this.state.selectedOptionIndex.secondaryIndex || 0]
|
|
182
|
+
: selectedOption;
|
|
183
|
+
}
|
|
184
|
+
buildListItem(option, isGroupTitle = false, groupIndex = null, index = -1, isSelected = false, className = "noseur-dropdown-popover-li-grp") {
|
|
185
|
+
if (isGroupTitle) {
|
|
186
|
+
return (React.createElement("li", { key: `${groupIndex || -2}-${index}`, "aria-label": option.label, role: "group", className: className, onClick: (_) => { } }, this.optionGroupTemplate(option)));
|
|
187
|
+
}
|
|
188
|
+
const optionElement = this.optionTemplate(option);
|
|
189
|
+
const refProps = {};
|
|
190
|
+
if (isSelected)
|
|
191
|
+
refProps.ref = (r) => r && this.functionStackManager.register("POPOVER_REFED", (popOverElement) => {
|
|
192
|
+
popOverElement.scrollTop = r.offsetTop - popOverElement.offsetTop;
|
|
193
|
+
});
|
|
194
|
+
return (React.createElement("li", { key: `${groupIndex || -1}-${index}`, "aria-label": option.label, role: "option", "aria-selected": isSelected, className: className, ref: (r) => r && isSelected && r.scrollIntoView(), ...refProps, onClick: (e) => {
|
|
195
|
+
if (this.props.disabled)
|
|
196
|
+
return;
|
|
197
|
+
this.selectOption(e, {
|
|
198
|
+
secondaryIndex: (groupIndex == null ? -1 : index),
|
|
199
|
+
primaryIndex: (groupIndex == null ? index : groupIndex),
|
|
200
|
+
}, option);
|
|
201
|
+
} }, optionElement));
|
|
202
|
+
}
|
|
203
|
+
renderOption(options, groupIndex = null, isSelectedGroup = false) {
|
|
204
|
+
const listItems = [];
|
|
205
|
+
const isGroupOptions = !!groupIndex;
|
|
206
|
+
const selectedOptionIndex = this.state.selectedOptionIndex;
|
|
207
|
+
options.forEach((option, index) => {
|
|
208
|
+
const trueSelectedIndex = isGroupOptions ? (isSelectedGroup ? selectedOptionIndex.secondaryIndex : -1) : selectedOptionIndex.primaryIndex;
|
|
209
|
+
const isSelected = index === trueSelectedIndex;
|
|
210
|
+
const isGroup = (this.props.optionGroupChildrenKey in option);
|
|
211
|
+
if (isGroup) {
|
|
212
|
+
listItems.push(this.buildListItem(option, true, index));
|
|
213
|
+
listItems.push(...this.renderOption(option[this.props.optionGroupChildrenKey], index, isSelected));
|
|
214
|
+
return;
|
|
215
|
+
}
|
|
216
|
+
const className = Classname.build((this.props.scheme && isSelected ? this.props.scheme : null), (this.props.scheme && !this.props.disabled ? `${this.props.scheme}-bg-hv` : null), {
|
|
217
|
+
'default-style': !this.props.scheme,
|
|
218
|
+
'noseur-disabled': option.not_selectable,
|
|
219
|
+
}, "noseur-dropdown-popover-li-item", this.props.optionsClassName, option.className);
|
|
220
|
+
listItems.push(this.buildListItem(option, false, groupIndex, index, isSelected, className));
|
|
221
|
+
});
|
|
222
|
+
return listItems;
|
|
223
|
+
}
|
|
224
|
+
buildSelectedOption(selectedOption) {
|
|
225
|
+
if (selectedOption && this.props.selectedOptionTemplate)
|
|
226
|
+
return this.props.selectedOptionTemplate(selectedOption);
|
|
227
|
+
let selectedOptionLabel = this.resolveOptionLabel(selectedOption);
|
|
228
|
+
if (this.props.translateSelectionLabel)
|
|
229
|
+
selectedOptionLabel = this.props.translateSelectionLabel(selectedOptionLabel, selectedOption);
|
|
230
|
+
let defaultValue = selectedOptionLabel;
|
|
231
|
+
const placeholder = (this.props.renderOptionAsPlaceholder && selectedOptionLabel ? selectedOptionLabel : this.props.placeholder);
|
|
232
|
+
if (defaultValue && this.props.renderOptionAsPlaceholder)
|
|
233
|
+
defaultValue = null;
|
|
234
|
+
if (!defaultValue)
|
|
235
|
+
defaultValue = this.props.textInputProps.defaultValue;
|
|
236
|
+
if (!defaultValue)
|
|
237
|
+
defaultValue = this.props.defaultInputValue;
|
|
238
|
+
const inputProps = {
|
|
239
|
+
placeholder,
|
|
240
|
+
defaultValue,
|
|
241
|
+
noStyle: true,
|
|
242
|
+
borderless: true,
|
|
243
|
+
id: this.props.id,
|
|
244
|
+
fill: this.props.fill,
|
|
245
|
+
scheme: this.props.scheme,
|
|
246
|
+
...this.props.textInputProps,
|
|
247
|
+
disabled: this.props.disabled,
|
|
248
|
+
readOnly: !this.props.editable,
|
|
249
|
+
highlight: this.props.highlight,
|
|
250
|
+
onInputComplete: this.props.onInputComplete,
|
|
251
|
+
style: { ...(this.props.style ?? {}), ...(this.props.textInputProps?.style ?? {}) },
|
|
252
|
+
ref: (el) => {
|
|
253
|
+
if (!el)
|
|
254
|
+
return;
|
|
255
|
+
this.internalTextInputElement = el;
|
|
256
|
+
if (!this.props.fill && this.props.responsiveWidth) {
|
|
257
|
+
const sidePaddings = parseInt(DOMHelper.getElementStyle(el).paddingLeft) + parseInt(DOMHelper.getElementStyle(el).paddingRight);
|
|
258
|
+
el.style.width = `${DOMHelper.getTextWidth((defaultValue ? defaultValue : placeholder), el) + sidePaddings}px`;
|
|
259
|
+
}
|
|
260
|
+
if (!this.props.textInputRef)
|
|
261
|
+
return;
|
|
262
|
+
if (this.props.textInputRef instanceof Function)
|
|
263
|
+
this.props.textInputRef(el);
|
|
264
|
+
else
|
|
265
|
+
this.props.textInputRef.current = el;
|
|
266
|
+
},
|
|
267
|
+
className: Classname.build('noseur-dropdown-inputtext', {
|
|
268
|
+
'noseur-cursor-pointer': !this.props.editable,
|
|
269
|
+
}, (this.props.textInputProps ?? {}).className, this.props.className),
|
|
270
|
+
};
|
|
271
|
+
if (!this.props.editable) {
|
|
272
|
+
inputProps.style.cursor = "pointer";
|
|
273
|
+
}
|
|
274
|
+
else if (this.props.onSearch) {
|
|
275
|
+
inputProps.onInput = (e) => {
|
|
276
|
+
if (this.props.onSearch) {
|
|
277
|
+
const options = this.props.onSearch(e, this.internalManageRefCache);
|
|
278
|
+
if (options === null)
|
|
279
|
+
return;
|
|
280
|
+
this.setState({ options });
|
|
281
|
+
}
|
|
282
|
+
};
|
|
283
|
+
}
|
|
284
|
+
return (React.createElement(TextInput, { ...inputProps, onClick: (e) => this.togglePopover(e, false) }));
|
|
285
|
+
}
|
|
286
|
+
renderPopover() {
|
|
287
|
+
let listItems;
|
|
288
|
+
const popoverProps = this.props.popoverProps ?? {};
|
|
289
|
+
popoverProps.matchTargetSize = !this.props.dontMatchTargetSize;
|
|
290
|
+
popoverProps.className = Classname.build("noseur-dropdown-popover", popoverProps.className);
|
|
291
|
+
if (this.state.options) {
|
|
292
|
+
if (!this.state.options.length && this.props.emptyTemplate)
|
|
293
|
+
listItems = this.props.emptyTemplate();
|
|
294
|
+
else
|
|
295
|
+
listItems = this.renderOption(this.state.options);
|
|
296
|
+
}
|
|
297
|
+
else {
|
|
298
|
+
listItems = this.props.loadingTemplate ? this.props.loadingTemplate() : (React.createElement("div", { className: "noseur-dropdown-popover-empty" },
|
|
299
|
+
React.createElement("i", { style: { fontSize: 30 }, className: "fa fa-spinner fa-spin" })));
|
|
300
|
+
}
|
|
301
|
+
const popoverHeader = (this.props.popoverHeaderTemplate) ? this.props.popoverHeaderTemplate() : null;
|
|
302
|
+
const popoverFooter = (this.props.popoverFooterTemplate) ? this.props.popoverFooterTemplate() : null;
|
|
303
|
+
const popoverItemsRef = (r) => {
|
|
304
|
+
r && this.functionStackManager.popSmoke("POPOVER_REFED", r);
|
|
305
|
+
};
|
|
306
|
+
return (React.createElement(Popover, { pointingArrowClassName: null, ...popoverProps, manageRef: (r) => this.internalPopoverElement = r, ref: this.props.popoverRef, onCloseFocusRef: this.props.textInputRef, onShow: this.onDropdownShow, onHide: this.onDropdownHide },
|
|
307
|
+
popoverHeader,
|
|
308
|
+
React.createElement("ul", { ref: popoverItemsRef, role: "listbox", className: "noseur-dropdown-popover-list" }, listItems),
|
|
309
|
+
popoverFooter));
|
|
310
|
+
}
|
|
311
|
+
renderToggleIcon() {
|
|
312
|
+
if (this.props.noToggleIcons)
|
|
313
|
+
return null;
|
|
314
|
+
const toggleIcon = this.props.toggleIcons[this.state.popoverVisible ? "hide" : "show"];
|
|
315
|
+
return TypeChecker.isString(toggleIcon)
|
|
316
|
+
? React.createElement("i", { className: Classname.build(toggleIcon, (this.props.scheme ? `${this.props.scheme}-tx` : null)) })
|
|
317
|
+
: toggleIcon;
|
|
318
|
+
}
|
|
319
|
+
renderLeftContent(selectedOption, formControlProps) {
|
|
320
|
+
const icon = this.props.iconPosition === Position.LEFT && !this.props.noSelectionIcon ? this.resolveOptionIcon(selectedOption) : null;
|
|
321
|
+
const leftContent = this.props.selectedOptionTemplate ? null : icon ?? formControlProps.leftContent;
|
|
322
|
+
const toggleIcon = this.props.togglePosition === Position.LEFT ? this.renderToggleIcon() : null;
|
|
323
|
+
if (!toggleIcon && !leftContent)
|
|
324
|
+
return null;
|
|
325
|
+
return (React.createElement("div", { className: "noseur-dropdown-left-content" },
|
|
326
|
+
toggleIcon,
|
|
327
|
+
leftContent));
|
|
328
|
+
}
|
|
329
|
+
renderRightContent(selectedOption, optionIsSelected) {
|
|
330
|
+
let closeIconClassname;
|
|
331
|
+
if (this.props.clearable && optionIsSelected) {
|
|
332
|
+
closeIconClassname = (React.createElement("i", { className: Classname.build("fa fa-close", `${Scheme.DANGER}-tx-hv`), onClick: (e) => {
|
|
333
|
+
e.stopPropagation();
|
|
334
|
+
this.selectOption(e, { primaryIndex: -1, secondaryIndex: -1 });
|
|
335
|
+
if (this.internalTextInputElement && this.props.renderOptionAsPlaceholder)
|
|
336
|
+
this.internalTextInputElement.placeholder = this.props.placeholder;
|
|
337
|
+
} }));
|
|
338
|
+
}
|
|
339
|
+
const icon = this.props.iconPosition === Position.RIGHT && !this.props.noSelectionIcon ? this.resolveOptionIcon(selectedOption) : null;
|
|
340
|
+
const toggleIcon = this.props.togglePosition === Position.RIGHT ? this.renderToggleIcon() : null;
|
|
341
|
+
if (!closeIconClassname && !toggleIcon && !icon)
|
|
342
|
+
return null;
|
|
343
|
+
return (React.createElement("div", { className: "noseur-dropdown-right-content" },
|
|
344
|
+
closeIconClassname,
|
|
345
|
+
icon,
|
|
346
|
+
toggleIcon));
|
|
347
|
+
}
|
|
348
|
+
render() {
|
|
349
|
+
const popover = this.renderPopover();
|
|
350
|
+
const selectedOption = this.getSelectedOption();
|
|
351
|
+
const formControlProps = (this.props.formControlProps || {});
|
|
352
|
+
const selectedOptionElement = this.buildSelectedOption(selectedOption);
|
|
353
|
+
const className = Classname.build('noseur-dropdown', this.props.formControlProps?.className, { "noseur-disabled": this.props.disabled });
|
|
354
|
+
return (React.createElement(React.Fragment, null,
|
|
355
|
+
React.createElement(FormControl, { ...formControlProps, className: className, borderless: this.props.borderless, leftContent: this.renderLeftContent(selectedOption, formControlProps), rightContent: this.renderRightContent(selectedOption, !!selectedOption), contentStyle: { width: "initial", ...(formControlProps.style || {}) }, fill: this.props.fill, scheme: this.props.scheme || formControlProps.scheme, ref: (r) => this.compoundElement = r, onClick: this.togglePopover }, selectedOptionElement),
|
|
356
|
+
popover));
|
|
357
|
+
}
|
|
358
|
+
}
|
|
359
|
+
export const Dropdown = ({ ref, ...props }) => (React.createElement(DropdownComponent, { ...props, forwardRef: ref }));
|
|
360
|
+
// TODO adapt size of selected label to input width
|
|
@@ -0,0 +1,134 @@
|
|
|
1
|
+
import "./Form.css";
|
|
2
|
+
import React from 'react';
|
|
3
|
+
import { BareInputManageRef } from "./Input";
|
|
4
|
+
import { Alignment } from "../constants/Alignment";
|
|
5
|
+
import { Orientation } from "../constants/Orientation";
|
|
6
|
+
import { NoseurElement, NoseurObject } from "../constants/Types";
|
|
7
|
+
import { ButtonProps } from "./Button";
|
|
8
|
+
import { ComponentBaseProps, ComponentElementBasicAttributes } from "../core/ComponentBaseProps";
|
|
9
|
+
export declare enum FileInputMode {
|
|
10
|
+
BUTTON = 0,
|
|
11
|
+
PREVIEW = 1,
|
|
12
|
+
ELEMENT = 2,
|
|
13
|
+
CONTROLLED = 3
|
|
14
|
+
}
|
|
15
|
+
export declare enum FileInputPreviewType {
|
|
16
|
+
PDF = "PDF",
|
|
17
|
+
AUTO = "AUTO",
|
|
18
|
+
NONE = "NONE",
|
|
19
|
+
HTML = "HTML",
|
|
20
|
+
TEXT = "TEXT",
|
|
21
|
+
IMAGE = "IMAGE",
|
|
22
|
+
VIDEO = "VIDEO",
|
|
23
|
+
AUDIO = "AUDIO",
|
|
24
|
+
BINARY = "BINARY",
|
|
25
|
+
CUSTOM = "CUSTOM"
|
|
26
|
+
}
|
|
27
|
+
export interface FileInputFixtureOptions {
|
|
28
|
+
className: string;
|
|
29
|
+
props: FileInputProps;
|
|
30
|
+
clearControl: NoseurElement;
|
|
31
|
+
selectControl: NoseurElement;
|
|
32
|
+
actionControl: NoseurElement;
|
|
33
|
+
}
|
|
34
|
+
export interface FileInputItemOptions {
|
|
35
|
+
file: File;
|
|
36
|
+
url: string;
|
|
37
|
+
index: number;
|
|
38
|
+
className: string;
|
|
39
|
+
props: FileInputProps;
|
|
40
|
+
formattedSize: string;
|
|
41
|
+
previewElement: NoseurElement;
|
|
42
|
+
onRemove: FileInputFileEventHandler;
|
|
43
|
+
}
|
|
44
|
+
export interface DragAndDropRefOptions {
|
|
45
|
+
count: number;
|
|
46
|
+
interval: number;
|
|
47
|
+
}
|
|
48
|
+
export type FileInputDialogEventHandler = (event: any) => void;
|
|
49
|
+
export type FileInputValidationHandler = (file: File) => string;
|
|
50
|
+
export type FileInputSelectFileHandler = (files: File[]) => void;
|
|
51
|
+
export type FileInputDragEventHandler = (event: DragEvent) => boolean;
|
|
52
|
+
export type FileInputFileEventHandler = (file: File, event?: Event) => void;
|
|
53
|
+
export type FileInputValidationEventHandler = (file: File, error: string) => boolean;
|
|
54
|
+
export type FileInputItemTemplateHandler = (options: FileInputItemOptions) => NoseurElement;
|
|
55
|
+
export type FileInputFixtureTemplateHandler = (options: FileInputFixtureOptions) => NoseurElement;
|
|
56
|
+
export type FileInputMountHandler = (onSelect?: (e?: any) => void, onDrop?: React.DragEventHandler<any>, onDragOver?: React.DragEventHandler<any>) => void;
|
|
57
|
+
export type FileInputEmptyTemplateHandler = (onSelect?: (e?: any) => void, onDrop?: React.DragEventHandler<any>, onDragOver?: React.DragEventHandler<any>) => NoseurElement;
|
|
58
|
+
export type FileInputAttributesRelays = {
|
|
59
|
+
control?: {
|
|
60
|
+
alignment?: Alignment;
|
|
61
|
+
} & ComponentElementBasicAttributes;
|
|
62
|
+
previews?: {
|
|
63
|
+
className?: string;
|
|
64
|
+
style?: React.CSSProperties;
|
|
65
|
+
};
|
|
66
|
+
preview?: {
|
|
67
|
+
className?: string;
|
|
68
|
+
style?: React.CSSProperties;
|
|
69
|
+
};
|
|
70
|
+
};
|
|
71
|
+
export interface FileInputManageRef extends BareInputManageRef<File> {
|
|
72
|
+
files: () => File[];
|
|
73
|
+
resolve: () => void;
|
|
74
|
+
select: (e?: Event) => void;
|
|
75
|
+
changeFiles: (files: File[]) => void;
|
|
76
|
+
}
|
|
77
|
+
export interface FileInputProps extends ComponentBaseProps<HTMLInputElement, FileInputManageRef, FileInputAttributesRelays> {
|
|
78
|
+
accepts: string;
|
|
79
|
+
rounded: boolean;
|
|
80
|
+
multiple: boolean;
|
|
81
|
+
selectOnly: boolean;
|
|
82
|
+
maxFileSize: number;
|
|
83
|
+
mode: FileInputMode;
|
|
84
|
+
defaultFiles: File[];
|
|
85
|
+
control: NoseurElement;
|
|
86
|
+
noDragAndDrop: boolean;
|
|
87
|
+
clickToChange: boolean;
|
|
88
|
+
stickyPreview: boolean;
|
|
89
|
+
concatNewFile: boolean;
|
|
90
|
+
orientation: Orientation;
|
|
91
|
+
controlIsManaged: boolean;
|
|
92
|
+
previewType: FileInputPreviewType;
|
|
93
|
+
buttonProps: Partial<ButtonProps>;
|
|
94
|
+
relayToAttachFileInputOnly: boolean;
|
|
95
|
+
elementProps: Partial<NoseurObject<any>>;
|
|
96
|
+
clearControl: Partial<ButtonProps> | NoseurElement;
|
|
97
|
+
selectControl: Partial<ButtonProps> | NoseurElement;
|
|
98
|
+
actionControl: Partial<ButtonProps> | NoseurElement;
|
|
99
|
+
dragAndDropRefOptions: Partial<DragAndDropRefOptions>;
|
|
100
|
+
dragAndDropRefs: React.MutableRefObject<HTMLElement>[];
|
|
101
|
+
attachFileInputManageRef: React.RefObject<FileInputManageRef | null>;
|
|
102
|
+
onMount: FileInputMountHandler;
|
|
103
|
+
onUnMount: FileInputMountHandler;
|
|
104
|
+
onDrop: React.DragEventHandler<any>;
|
|
105
|
+
onAction: FileInputSelectFileHandler;
|
|
106
|
+
onDragOver: React.DragEventHandler<any>;
|
|
107
|
+
onRemoveFile: FileInputFileEventHandler;
|
|
108
|
+
onBeforeDrop: FileInputDragEventHandler;
|
|
109
|
+
onDragBegin: React.DragEventHandler<any>;
|
|
110
|
+
validateFile: FileInputValidationHandler;
|
|
111
|
+
onSelectFiles: FileInputSelectFileHandler;
|
|
112
|
+
itemTemplate: FileInputItemTemplateHandler;
|
|
113
|
+
onDragComplete: React.DragEventHandler<any>;
|
|
114
|
+
onCancelDialog: FileInputDialogEventHandler;
|
|
115
|
+
emptyTemplate: FileInputEmptyTemplateHandler;
|
|
116
|
+
onConfirmDialog: FileInputDialogEventHandler;
|
|
117
|
+
headerTemplate: FileInputFixtureTemplateHandler;
|
|
118
|
+
footerTemplate: FileInputFixtureTemplateHandler;
|
|
119
|
+
onValidationFail: FileInputValidationEventHandler;
|
|
120
|
+
}
|
|
121
|
+
export declare const FileInput: ({ ref, ...props }: Partial<FileInputProps>) => React.JSX.Element;
|
|
122
|
+
export interface FileInputPreviewOption {
|
|
123
|
+
file?: File;
|
|
124
|
+
alt?: string;
|
|
125
|
+
url?: string;
|
|
126
|
+
formattedSize?: string;
|
|
127
|
+
style?: React.CSSProperties;
|
|
128
|
+
ref?: React.ForwardedRef<any>;
|
|
129
|
+
previewType?: FileInputPreviewType;
|
|
130
|
+
onRemove?: FileInputFileEventHandler;
|
|
131
|
+
removeButton?: React.ReactElement<ButtonProps, string | React.JSXElementConstructor<ButtonProps>>;
|
|
132
|
+
}
|
|
133
|
+
export declare function fileInputBuildFileInputPreview(options: FileInputPreviewOption): React.JSX.Element;
|
|
134
|
+
export declare function fileInputFileFromUrl(url: string, name?: string, type?: string): File;
|