haya-select 1.0.27 → 1.0.29
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/package.json +2 -2
- package/src/select/index.jsx +78 -63
- package/src/select/option-group.jsx +13 -12
- package/src/select/option.jsx +27 -27
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "haya-select",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.29",
|
|
4
4
|
"description": "",
|
|
5
5
|
"main": "index.js",
|
|
6
6
|
"scripts": {
|
|
@@ -13,7 +13,7 @@
|
|
|
13
13
|
"debounce": "^1.2.1",
|
|
14
14
|
"diggerize": "^1.0.4",
|
|
15
15
|
"fetching-object": "^1.0.1",
|
|
16
|
-
"set-state-compare": "^1.0.
|
|
16
|
+
"set-state-compare": "^1.0.42"
|
|
17
17
|
},
|
|
18
18
|
"peerDependencies": {
|
|
19
19
|
"prop-types": ">= 15.7.2",
|
package/src/select/index.jsx
CHANGED
|
@@ -9,8 +9,8 @@ import nameForComponent from "@kaspernj/api-maker/src/inputs/name-for-component.
|
|
|
9
9
|
import Option from "./option"
|
|
10
10
|
import OptionGroup from "./option-group"
|
|
11
11
|
import PropTypes from "prop-types"
|
|
12
|
-
import
|
|
13
|
-
import {
|
|
12
|
+
import {memo, useRef} from "react"
|
|
13
|
+
import {shapeComponent, ShapeComponent} from "set-state-compare/src/shape-component.js"
|
|
14
14
|
|
|
15
15
|
const nameForComponentWithMultiple = (component) => {
|
|
16
16
|
let name = nameForComponent(component)
|
|
@@ -20,7 +20,7 @@ const nameForComponentWithMultiple = (component) => {
|
|
|
20
20
|
return name
|
|
21
21
|
}
|
|
22
22
|
|
|
23
|
-
export default class HayaSelect extends
|
|
23
|
+
export default memo(shapeComponent(class HayaSelect extends ShapeComponent {
|
|
24
24
|
static defaultProps = {
|
|
25
25
|
multiple: false,
|
|
26
26
|
search: false
|
|
@@ -51,27 +51,33 @@ export default class HayaSelect extends React.PureComponent {
|
|
|
51
51
|
}
|
|
52
52
|
|
|
53
53
|
p = fetchingObject(() => this.props)
|
|
54
|
-
s = fetchingObject(() => this.
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
54
|
+
s = fetchingObject(() => this.state)
|
|
55
|
+
tt = fetchingObject(this)
|
|
56
|
+
|
|
57
|
+
setup() {
|
|
58
|
+
const {t} = useI18n({namespace: "haya_select"})
|
|
59
|
+
|
|
60
|
+
this.setInstance({
|
|
61
|
+
endOfSelectRef: useRef(),
|
|
62
|
+
optionsContainerRef: useRef(),
|
|
63
|
+
currentSelectedRef: useRef(),
|
|
64
|
+
searchTextInputRef: useRef(),
|
|
65
|
+
t
|
|
66
|
+
})
|
|
67
|
+
this.useStates({
|
|
68
|
+
currentOptions: () => this.defaultCurrentOptions(),
|
|
69
|
+
loadedOptions: () => this.defaultLoadedOptions(),
|
|
70
|
+
opened: false,
|
|
71
|
+
optionsLeft: undefined,
|
|
72
|
+
optionsPlacement: undefined,
|
|
73
|
+
optionsTop: undefined,
|
|
74
|
+
optionsVisibility: undefined,
|
|
75
|
+
optionsWidth: undefined,
|
|
76
|
+
scrollLeft: undefined,
|
|
77
|
+
scrollTop: undefined,
|
|
78
|
+
toggled: () => this.defaultToggled()
|
|
79
|
+
})
|
|
80
|
+
}
|
|
75
81
|
|
|
76
82
|
defaultCurrentOptions() {
|
|
77
83
|
const {defaultValue, defaultValues, values} = this.props
|
|
@@ -109,8 +115,8 @@ export default class HayaSelect extends React.PureComponent {
|
|
|
109
115
|
this.loadDefaultValuesFromOptionsCallback()
|
|
110
116
|
}
|
|
111
117
|
|
|
112
|
-
window.addEventListener("resize", this.
|
|
113
|
-
window.addEventListener("scroll", this.
|
|
118
|
+
window.addEventListener("resize", this.tt.onAnythingResizedDebounced, true)
|
|
119
|
+
window.addEventListener("scroll", this.tt.onAnythingScrolledDebounced, true)
|
|
114
120
|
}
|
|
115
121
|
|
|
116
122
|
componentDidUpdate() {
|
|
@@ -119,7 +125,7 @@ export default class HayaSelect extends React.PureComponent {
|
|
|
119
125
|
if ("values" in this.props) {
|
|
120
126
|
const newCurrentOptions = this.defaultCurrentOptions()
|
|
121
127
|
|
|
122
|
-
if (anythingDifferent(this.
|
|
128
|
+
if (anythingDifferent(this.state.currentOptions, newCurrentOptions)) {
|
|
123
129
|
newState.currentOptions = newCurrentOptions
|
|
124
130
|
}
|
|
125
131
|
}
|
|
@@ -127,21 +133,21 @@ export default class HayaSelect extends React.PureComponent {
|
|
|
127
133
|
if ("toggled" in this.props) {
|
|
128
134
|
const newToggled = this.p.toggled
|
|
129
135
|
|
|
130
|
-
if (anythingDifferent(this.
|
|
136
|
+
if (anythingDifferent(this.state.toggled, newToggled)) {
|
|
131
137
|
newState.toggled = newToggled
|
|
132
138
|
}
|
|
133
139
|
}
|
|
134
140
|
|
|
135
|
-
this.
|
|
141
|
+
this.setState(newState)
|
|
136
142
|
}
|
|
137
143
|
|
|
138
144
|
componentWillUnmount() {
|
|
139
|
-
window.removeEventListener("resize", this.
|
|
140
|
-
window.removeEventListener("scroll", this.
|
|
145
|
+
window.removeEventListener("resize", this.tt.onAnythingResizedDebounced)
|
|
146
|
+
window.removeEventListener("scroll", this.tt.onAnythingScrolledDebounced)
|
|
141
147
|
}
|
|
142
148
|
|
|
143
149
|
render() {
|
|
144
|
-
const {currentSelectedRef, endOfSelectRef, onSelectClicked, onSearchTextInputChangedDebounced} = this.
|
|
150
|
+
const {currentSelectedRef, endOfSelectRef, onSelectClicked, onSearchTextInputChangedDebounced} = this.tt
|
|
145
151
|
const {
|
|
146
152
|
attribute,
|
|
147
153
|
className,
|
|
@@ -151,6 +157,7 @@ export default class HayaSelect extends React.PureComponent {
|
|
|
151
157
|
id,
|
|
152
158
|
model,
|
|
153
159
|
multiple,
|
|
160
|
+
name,
|
|
154
161
|
onChange,
|
|
155
162
|
onOptionsClosed,
|
|
156
163
|
options,
|
|
@@ -185,18 +192,26 @@ export default class HayaSelect extends React.PureComponent {
|
|
|
185
192
|
<input
|
|
186
193
|
className="haya-select-search-text-input"
|
|
187
194
|
onChange={onSearchTextInputChangedDebounced}
|
|
188
|
-
placeholder={
|
|
195
|
+
placeholder={this.t(".search_dot_dot_dot")}
|
|
189
196
|
type="text"
|
|
190
|
-
ref={this.
|
|
197
|
+
ref={this.tt.searchTextInputRef}
|
|
191
198
|
/>
|
|
192
199
|
}
|
|
193
200
|
{!opened &&
|
|
194
201
|
<>
|
|
195
202
|
{currentOptions.length == 0 &&
|
|
196
203
|
<div style={{color: "grey"}}>
|
|
197
|
-
{placeholder ||
|
|
204
|
+
{placeholder || this.t(".nothing_selected")}
|
|
198
205
|
</div>
|
|
199
206
|
}
|
|
207
|
+
{currentOptions.length == 0 &&
|
|
208
|
+
<input
|
|
209
|
+
id={idForComponent(this)}
|
|
210
|
+
name={nameForComponentWithMultiple(this)}
|
|
211
|
+
type="hidden"
|
|
212
|
+
value=""
|
|
213
|
+
/>
|
|
214
|
+
}
|
|
200
215
|
{currentOptions.map((currentOption) =>
|
|
201
216
|
<div className="current-option" key={currentOption.key || `current-value-${currentOption.value}`}>
|
|
202
217
|
{currentOption.type == "group" &&
|
|
@@ -246,7 +261,7 @@ export default class HayaSelect extends React.PureComponent {
|
|
|
246
261
|
}
|
|
247
262
|
|
|
248
263
|
isActive() {
|
|
249
|
-
if (this.
|
|
264
|
+
if (this.tt.endOfSelectRef.current) {
|
|
250
265
|
return true
|
|
251
266
|
}
|
|
252
267
|
|
|
@@ -259,16 +274,16 @@ export default class HayaSelect extends React.PureComponent {
|
|
|
259
274
|
if (!defaultValues) return
|
|
260
275
|
|
|
261
276
|
const result = await this.props.options({
|
|
262
|
-
searchValue: digg(this.
|
|
277
|
+
searchValue: digg(this.tt.searchTextInputRef, "current")?.value,
|
|
263
278
|
values: defaultValues
|
|
264
279
|
})
|
|
265
280
|
|
|
266
|
-
this.
|
|
281
|
+
this.setState({currentOptions: this.state.currentOptions.concat(result)})
|
|
267
282
|
}
|
|
268
283
|
|
|
269
284
|
loadOptions = async () => {
|
|
270
285
|
const {options} = this.p
|
|
271
|
-
const searchValue = digg(this.
|
|
286
|
+
const searchValue = digg(this.tt.searchTextInputRef, "current")?.value
|
|
272
287
|
|
|
273
288
|
if (Array.isArray(options)) {
|
|
274
289
|
return this.loadOptionsFromArray(options, searchValue)
|
|
@@ -276,7 +291,7 @@ export default class HayaSelect extends React.PureComponent {
|
|
|
276
291
|
|
|
277
292
|
const loadedOptions = await options({searchValue})
|
|
278
293
|
|
|
279
|
-
this.
|
|
294
|
+
this.setState({loadedOptions})
|
|
280
295
|
}
|
|
281
296
|
|
|
282
297
|
hayaSelectOption({key, loadedOption}) {
|
|
@@ -285,7 +300,7 @@ export default class HayaSelect extends React.PureComponent {
|
|
|
285
300
|
}
|
|
286
301
|
|
|
287
302
|
return <Option
|
|
288
|
-
currentOptions={this.
|
|
303
|
+
currentOptions={this.state.currentOptions}
|
|
289
304
|
icon={this.iconForOption(loadedOption)}
|
|
290
305
|
key={key}
|
|
291
306
|
option={loadedOption}
|
|
@@ -298,7 +313,7 @@ export default class HayaSelect extends React.PureComponent {
|
|
|
298
313
|
const lowerSearchValue = searchValue?.toLowerCase()
|
|
299
314
|
const loadedOptions = options.filter(({text}) => !lowerSearchValue || text.toLowerCase().includes(lowerSearchValue))
|
|
300
315
|
|
|
301
|
-
this.
|
|
316
|
+
this.setState({loadedOptions})
|
|
302
317
|
}
|
|
303
318
|
|
|
304
319
|
onSelectClicked = (e) => {
|
|
@@ -314,23 +329,23 @@ export default class HayaSelect extends React.PureComponent {
|
|
|
314
329
|
}
|
|
315
330
|
}
|
|
316
331
|
|
|
317
|
-
onSearchTextInputChangedDebounced = debounce(this.
|
|
332
|
+
onSearchTextInputChangedDebounced = debounce(this.tt.loadOptions, 200)
|
|
318
333
|
|
|
319
334
|
closeOptions() {
|
|
320
|
-
this.
|
|
335
|
+
this.setState({
|
|
321
336
|
loadedOptions: undefined,
|
|
322
337
|
opened: false
|
|
323
338
|
})
|
|
324
339
|
|
|
325
340
|
if (this.props.onOptionsClosed) {
|
|
326
|
-
this.props.onOptionsClosed({options: this.
|
|
341
|
+
this.props.onOptionsClosed({options: this.state.currentOptions})
|
|
327
342
|
}
|
|
328
343
|
}
|
|
329
344
|
|
|
330
345
|
openOptions() {
|
|
331
346
|
this.setOptionsPositionBelow()
|
|
332
347
|
this.loadOptions()
|
|
333
|
-
this.
|
|
348
|
+
this.setState(
|
|
334
349
|
{opened: true},
|
|
335
350
|
() => {
|
|
336
351
|
this.focusTextInput()
|
|
@@ -339,7 +354,7 @@ export default class HayaSelect extends React.PureComponent {
|
|
|
339
354
|
)
|
|
340
355
|
}
|
|
341
356
|
|
|
342
|
-
focusTextInput = () => digg(this.
|
|
357
|
+
focusTextInput = () => digg(this.tt.searchTextInputRef, "current").focus()
|
|
343
358
|
|
|
344
359
|
setOptionsPosition() {
|
|
345
360
|
if (!this.isActive()) return // Debounce after un-mount handeling.
|
|
@@ -349,7 +364,7 @@ export default class HayaSelect extends React.PureComponent {
|
|
|
349
364
|
}
|
|
350
365
|
|
|
351
366
|
setOptionsPositionAboveIfOutsideScreen() {
|
|
352
|
-
const {optionsContainerRef} = this.
|
|
367
|
+
const {optionsContainerRef} = this.tt
|
|
353
368
|
const {optionsTop} = this.s
|
|
354
369
|
const optionsHeight = digg(optionsContainerRef, "current", "offsetHeight")
|
|
355
370
|
const scrollTop = document.documentElement.scrollTop
|
|
@@ -358,18 +373,18 @@ export default class HayaSelect extends React.PureComponent {
|
|
|
358
373
|
if (window.innerHeight < optionsTotalHeight) {
|
|
359
374
|
this.setOptionsPositionAbove()
|
|
360
375
|
} else {
|
|
361
|
-
this.
|
|
376
|
+
this.setState({optionsVisibility: "visible"})
|
|
362
377
|
}
|
|
363
378
|
}
|
|
364
379
|
|
|
365
380
|
setOptionsPositionAbove() {
|
|
366
|
-
const {optionsContainerRef, currentSelectedRef, searchTextInputRef} = this.
|
|
381
|
+
const {optionsContainerRef, currentSelectedRef, searchTextInputRef} = this.tt
|
|
367
382
|
const optionsHeight = digg(optionsContainerRef, "current", "offsetHeight")
|
|
368
383
|
const position = currentSelectedRef.current.getBoundingClientRect()
|
|
369
384
|
const {left, top, width} = digs(position, "left", "top", "width")
|
|
370
385
|
const optionsTop = top - optionsHeight + 2
|
|
371
386
|
|
|
372
|
-
this.
|
|
387
|
+
this.setState(
|
|
373
388
|
{
|
|
374
389
|
opened: true,
|
|
375
390
|
optionsLeft: left,
|
|
@@ -385,11 +400,11 @@ export default class HayaSelect extends React.PureComponent {
|
|
|
385
400
|
}
|
|
386
401
|
|
|
387
402
|
setOptionsPositionBelow() {
|
|
388
|
-
const {endOfSelectRef, searchTextInputRef} = this.
|
|
403
|
+
const {endOfSelectRef, searchTextInputRef} = this.tt
|
|
389
404
|
const position = endOfSelectRef.current.getBoundingClientRect()
|
|
390
405
|
const {left, top, width} = digs(position, "left", "top", "width")
|
|
391
406
|
|
|
392
|
-
this.
|
|
407
|
+
this.setState(
|
|
393
408
|
{
|
|
394
409
|
opened: true,
|
|
395
410
|
optionsLeft: left,
|
|
@@ -410,7 +425,7 @@ export default class HayaSelect extends React.PureComponent {
|
|
|
410
425
|
}
|
|
411
426
|
}
|
|
412
427
|
|
|
413
|
-
onAnythingResizedDebounced = debounce(this.
|
|
428
|
+
onAnythingResizedDebounced = debounce(this.tt.onAnythingResized, 25)
|
|
414
429
|
|
|
415
430
|
onAnythingScrolled = (e) => {
|
|
416
431
|
if (this.s.opened) {
|
|
@@ -418,10 +433,10 @@ export default class HayaSelect extends React.PureComponent {
|
|
|
418
433
|
}
|
|
419
434
|
}
|
|
420
435
|
|
|
421
|
-
onAnythingScrolledDebounced = debounce(this.
|
|
436
|
+
onAnythingScrolledDebounced = debounce(this.tt.onAnythingScrolled, 25)
|
|
422
437
|
|
|
423
438
|
onWindowClicked = (e) => {
|
|
424
|
-
const {optionsContainerRef} = this.
|
|
439
|
+
const {optionsContainerRef} = this.tt
|
|
425
440
|
const {opened} = this.s
|
|
426
441
|
|
|
427
442
|
// If options are open and a click is made outside of the options container
|
|
@@ -431,7 +446,7 @@ export default class HayaSelect extends React.PureComponent {
|
|
|
431
446
|
}
|
|
432
447
|
|
|
433
448
|
optionsContainer() {
|
|
434
|
-
const {optionsContainerRef} = this.
|
|
449
|
+
const {optionsContainerRef} = this.tt
|
|
435
450
|
const {loadedOptions, optionsLeft, optionsTop, optionsVisibility, optionsWidth, scrollLeft, scrollTop} = this.s
|
|
436
451
|
|
|
437
452
|
return (
|
|
@@ -455,7 +470,7 @@ export default class HayaSelect extends React.PureComponent {
|
|
|
455
470
|
)}
|
|
456
471
|
{loadedOptions?.length === 0 &&
|
|
457
472
|
<div className="haya-select-no-options-container">
|
|
458
|
-
{
|
|
473
|
+
{this.t(".no_options_found")}
|
|
459
474
|
</div>
|
|
460
475
|
}
|
|
461
476
|
</div>
|
|
@@ -468,7 +483,7 @@ export default class HayaSelect extends React.PureComponent {
|
|
|
468
483
|
|
|
469
484
|
const {onChange, toggleOptions} = this.props
|
|
470
485
|
const {multiple} = this.p
|
|
471
|
-
const {currentOptions, toggled} = this.
|
|
486
|
+
const {currentOptions, toggled} = this.state
|
|
472
487
|
const newState = {}
|
|
473
488
|
const existingOption = currentOptions.find((currentOption) => currentOption.value == loadedOption.value)
|
|
474
489
|
const newToggled = {...toggled}
|
|
@@ -505,12 +520,12 @@ export default class HayaSelect extends React.PureComponent {
|
|
|
505
520
|
}
|
|
506
521
|
}
|
|
507
522
|
|
|
508
|
-
this.
|
|
523
|
+
this.setState(newState)
|
|
509
524
|
|
|
510
525
|
if (onChange) {
|
|
511
526
|
const toggles = {}
|
|
512
527
|
|
|
513
|
-
for(const toggleKey in this.
|
|
528
|
+
for(const toggleKey in this.state.toggled) {
|
|
514
529
|
const toggleValue = digg(this.s.toggled, toggleKey)
|
|
515
530
|
const toggleOption = digg(this.p.toggleOptions, toggleValue)
|
|
516
531
|
|
|
@@ -519,7 +534,7 @@ export default class HayaSelect extends React.PureComponent {
|
|
|
519
534
|
|
|
520
535
|
onChange({
|
|
521
536
|
event,
|
|
522
|
-
options: this.
|
|
537
|
+
options: this.state.currentOptions,
|
|
523
538
|
toggles
|
|
524
539
|
})
|
|
525
540
|
}
|
|
@@ -564,4 +579,4 @@ export default class HayaSelect extends React.PureComponent {
|
|
|
564
579
|
</div>
|
|
565
580
|
)
|
|
566
581
|
}
|
|
567
|
-
}
|
|
582
|
+
}))
|
|
@@ -1,16 +1,17 @@
|
|
|
1
1
|
import PropTypes from "prop-types"
|
|
2
2
|
import {memo} from "react"
|
|
3
|
+
import {shapeComponent, ShapeComponent} from "set-state-compare/src/shape-component.js"
|
|
3
4
|
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
</div>
|
|
9
|
-
)
|
|
10
|
-
}
|
|
5
|
+
export default memo(shapeComponent(class OptionGroup extends ShapeComponent {
|
|
6
|
+
static propTypes = {
|
|
7
|
+
option: PropTypes.object.isRequired
|
|
8
|
+
}
|
|
11
9
|
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
10
|
+
render() {
|
|
11
|
+
return (
|
|
12
|
+
<div className="haya-select--option-group">
|
|
13
|
+
{option.text}
|
|
14
|
+
</div>
|
|
15
|
+
)
|
|
16
|
+
}
|
|
17
|
+
}))
|
package/src/select/option.jsx
CHANGED
|
@@ -1,32 +1,32 @@
|
|
|
1
1
|
import PropTypes from "prop-types"
|
|
2
|
-
import {memo
|
|
3
|
-
import
|
|
2
|
+
import {memo} from "react"
|
|
3
|
+
import {shapeComponent, ShapeComponent} from "set-state-compare/src/shape-component.js"
|
|
4
4
|
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
5
|
+
export default memo(shapeComponent(class Option extends ShapeComponent {
|
|
6
|
+
static propTypes = {
|
|
7
|
+
currentOptions: PropTypes.array.isRequired,
|
|
8
|
+
disabled: PropTypes.bool,
|
|
9
|
+
icon: PropTypes.string,
|
|
10
|
+
onOptionClicked: PropTypes.func.isRequired,
|
|
11
|
+
option: PropTypes.object.isRequired,
|
|
12
|
+
presentOption: PropTypes.func.isRequired
|
|
13
|
+
}
|
|
9
14
|
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
className="haya-select-option"
|
|
13
|
-
data-disabled={Boolean(s.p.option.disabled)}
|
|
14
|
-
data-selected={selected}
|
|
15
|
-
data-value={s.p.option.value}
|
|
16
|
-
onClick={onClick}
|
|
17
|
-
>
|
|
18
|
-
{props.presentOption(s.p.option)}
|
|
19
|
-
</div>
|
|
20
|
-
)
|
|
21
|
-
}
|
|
15
|
+
render() {
|
|
16
|
+
const selected = Boolean(this.props.currentOptions.find((currentOption) => currentOption.value == this.props.option.value))
|
|
22
17
|
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
18
|
+
return (
|
|
19
|
+
<div
|
|
20
|
+
className="haya-select-option"
|
|
21
|
+
data-disabled={Boolean(this.props.option.disabled)}
|
|
22
|
+
data-selected={selected}
|
|
23
|
+
data-value={this.props.option.value}
|
|
24
|
+
onClick={this.onClick}
|
|
25
|
+
>
|
|
26
|
+
{props.presentOption(this.props.option)}
|
|
27
|
+
</div>
|
|
28
|
+
)
|
|
29
|
+
}
|
|
31
30
|
|
|
32
|
-
|
|
31
|
+
onClick = (e) => this.props.onOptionClicked(e, this.props.option)
|
|
32
|
+
}))
|