haya-select 1.0.6 → 1.0.9

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.
@@ -0,0 +1,9 @@
1
+ version: 2
2
+ updates:
3
+ - package-ecosystem: npm
4
+ directory: "/"
5
+ schedule:
6
+ interval: weekly
7
+ time: "01:00"
8
+ timezone: Europe/Copenhagen
9
+ open-pull-requests-limit: 99
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "haya-select",
3
- "version": "1.0.6",
3
+ "version": "1.0.9",
4
4
  "description": "",
5
5
  "main": "index.js",
6
6
  "scripts": {
@@ -12,5 +12,9 @@
12
12
  "classnames": "^2.3.1",
13
13
  "debounce": "^1.2.1",
14
14
  "diggerize": "^1.0.4"
15
+ },
16
+ "peerDependencies": {
17
+ "prop-types": ">= 15.7.2",
18
+ "react": ">= 16.0.0"
15
19
  }
16
20
  }
@@ -14,41 +14,9 @@ const nameForComponentWithMultiple = (component) => {
14
14
  return name
15
15
  }
16
16
 
17
- const presentOption = (currentValue) => {
18
- if ("text" in currentValue) return currentValue.text
19
-
20
- if ("html" in currentValue) {
21
- return (
22
- <div dangerouslySetInnerHTML={{__html: digg(currentValue, "html")}} />
23
- )
24
- }
25
-
26
- throw new Error(`Couldn't figure out how to present option from the given keys: ${Object.keys(currentValue, ", ")}`)
27
- }
28
-
29
- const LoadedOption = class LoadedOption extends BaseComponent {
30
- render() {
31
- const {currentOptions, loadedOption} = digs(this.props, "currentOptions", "loadedOption")
32
- const selected = Boolean(currentOptions.find((currentOption) => currentOption.value == loadedOption.value))
33
-
34
- return (
35
- <div
36
- className="haya-select-option"
37
- data-selected={selected}
38
- data-value={digg(loadedOption, "value")}
39
- onClick={this.onOptionClicked}
40
- style={{cursor: "pointer"}}
41
- >
42
- {presentOption(loadedOption)}
43
- </div>
44
- )
45
- }
46
-
47
- onOptionClicked = (e) => this.props.onClick(e, this.props.loadedOption)
48
- }
49
-
50
- export default class CustomSelect extends React.PureComponent {
17
+ export default class HayaSelect extends React.PureComponent {
51
18
  static defaultProps = {
19
+ defaultToggled: {},
52
20
  multiple: false,
53
21
  search: false
54
22
  }
@@ -56,14 +24,22 @@ export default class CustomSelect extends React.PureComponent {
56
24
  static propTypes = {
57
25
  attribute: PropTypes.string,
58
26
  className: PropTypes.string,
27
+ defaultToggled: PropTypes.object,
59
28
  defaultValue: PropTypes.oneOfType([PropTypes.number, PropTypes.string]),
60
29
  defaultValues: PropTypes.array,
61
30
  defaultValuesFromOptions: PropTypes.array,
31
+ id: PropTypes.node,
62
32
  model: PropTypes.object,
63
33
  multiple: PropTypes.bool.isRequired,
64
34
  onChange: PropTypes.func,
65
35
  options: PropTypes.oneOfType([PropTypes.array, PropTypes.func]).isRequired,
66
- search: PropTypes.bool.isRequired
36
+ placeholder: PropTypes.node,
37
+ search: PropTypes.bool.isRequired,
38
+ toggleOptions: PropTypes.arrayOf(PropTypes.shape({
39
+ icon: PropTypes.string.isRequired,
40
+ label: PropTypes.string.isRequired,
41
+ value: PropTypes.string.isRequired
42
+ }))
67
43
  }
68
44
 
69
45
  endOfSelectRef = React.createRef()
@@ -78,7 +54,8 @@ export default class CustomSelect extends React.PureComponent {
78
54
  optionsTop: undefined,
79
55
  optionsWidth: undefined,
80
56
  scrollLeft: undefined,
81
- scrollTop: undefined
57
+ scrollTop: undefined,
58
+ toggled: digg(this, "props", "defaultToggled")
82
59
  }
83
60
 
84
61
  defaultCurrentOptions() {
@@ -106,16 +83,31 @@ export default class CustomSelect extends React.PureComponent {
106
83
  }
107
84
 
108
85
  componentDidMount() {
109
- const {attribute, defaultValuesFromOptions, model, options} = this.props
86
+ const {attribute, defaultValue, defaultValuesFromOptions, model, options} = this.props
110
87
 
111
- if ((defaultValuesFromOptions || (attribute && model)) && typeof options == "function") {
88
+ if (((defaultValue || defaultValuesFromOptions) || (attribute && model)) && typeof options == "function") {
112
89
  this.loadDefaultValuesFromOptionsCallback()
113
90
  }
114
91
  }
115
92
 
116
93
  render() {
117
94
  const {endOfSelectRef} = digs(this, "endOfSelectRef")
118
- const {attribute, className, defaultValue, defaultValues, model, multiple, onChange, options, search, ...restProps} = this.props
95
+ const {
96
+ attribute,
97
+ className,
98
+ defaultToggled,
99
+ defaultValue,
100
+ defaultValues,
101
+ id,
102
+ model,
103
+ multiple,
104
+ onChange,
105
+ options,
106
+ placeholder,
107
+ search,
108
+ toggleOptions,
109
+ ...restProps
110
+ } = this.props
119
111
  const {currentOptions, opened} = digs(this.state, "currentOptions", "opened")
120
112
  const BodyPortal = config.getBodyPortal()
121
113
 
@@ -147,18 +139,20 @@ export default class CustomSelect extends React.PureComponent {
147
139
  <>
148
140
  {currentOptions.length == 0 &&
149
141
  <div style={{color: "grey"}}>
150
- {I18n.t("haya_select.nothing_selected")}
142
+ {placeholder || I18n.t("haya_select.nothing_selected")}
151
143
  </div>
152
144
  }
153
145
  {currentOptions.map((currentOption) =>
154
146
  <div className="current-option" key={`current-value-${digg(currentOption, "value")}`}>
155
- <input
156
- id={idForComponent(this)}
157
- name={nameForComponentWithMultiple(this)}
158
- type="hidden"
159
- value={digg(currentOption, "value")}
160
- />
161
- {presentOption(currentOption)}
147
+ {nameForComponentWithMultiple(this) &&
148
+ <input
149
+ id={idForComponent(this)}
150
+ name={nameForComponentWithMultiple(this)}
151
+ type="hidden"
152
+ value={digg(currentOption, "value")}
153
+ />
154
+ }
155
+ {this.presentOption(currentOption)}
162
156
  </div>
163
157
  )}
164
158
  </>
@@ -170,9 +164,10 @@ export default class CustomSelect extends React.PureComponent {
170
164
  }
171
165
 
172
166
  defaultValues () {
173
- const {attribute, defaultValuesFromOptions, model} = this.props
167
+ const {attribute, defaultValue, defaultValuesFromOptions, model} = this.props
174
168
 
175
169
  if (defaultValuesFromOptions) return defaultValuesFromOptions
170
+ if (defaultValue) return defaultValue
176
171
 
177
172
  if (attribute && model) {
178
173
  if (!(attribute in model)) throw new Error(`No such attribute on ${model.modelClassData().name}: ${attribute}`)
@@ -209,6 +204,24 @@ export default class CustomSelect extends React.PureComponent {
209
204
  this.setState({loadedOptions})
210
205
  }
211
206
 
207
+ hayaSelectOption({key, loadedOption}) {
208
+ const {currentOptions} = digs(this.state, "currentOptions")
209
+ const selected = Boolean(currentOptions.find((currentOption) => currentOption.value == loadedOption.value))
210
+
211
+ return (
212
+ <div
213
+ className="haya-select-option"
214
+ data-selected={selected}
215
+ data-value={digg(loadedOption, "value")}
216
+ key={key}
217
+ onClick={(e) => this.onOptionClicked(e, loadedOption)}
218
+ style={{cursor: "pointer"}}
219
+ >
220
+ {this.presentOption(loadedOption)}
221
+ </div>
222
+ )
223
+ }
224
+
212
225
  loadOptionsFromArray(options, searchValue) {
213
226
  const lowerSearchValue = searchValue?.toLowerCase()
214
227
  const loadedOptions = options.filter(({text}) => !lowerSearchValue || text.toLowerCase().includes(lowerSearchValue))
@@ -273,7 +286,6 @@ export default class CustomSelect extends React.PureComponent {
273
286
  optionsContainer() {
274
287
  const {optionsContainerRef} = digs(this, "endOfSelectRef", "optionsContainerRef")
275
288
  const {
276
- currentOptions,
277
289
  loadedOptions,
278
290
  optionsLeft,
279
291
  optionsTop,
@@ -282,7 +294,6 @@ export default class CustomSelect extends React.PureComponent {
282
294
  scrollTop
283
295
  } = digs(
284
296
  this.state,
285
- "currentOptions",
286
297
  "loadedOptions",
287
298
  "currentOptions",
288
299
  "opened",
@@ -306,12 +317,10 @@ export default class CustomSelect extends React.PureComponent {
306
317
  >
307
318
  <EventListener event="click" onCalled={this.onWindowClicked} target={window} />
308
319
  {loadedOptions?.map((loadedOption) =>
309
- <LoadedOption
310
- currentOptions={currentOptions}
311
- key={`loaded-option-${digg(loadedOption.value)}`}
312
- loadedOption={loadedOption}
313
- onClick={this.onOptionClicked}
314
- />
320
+ this.hayaSelectOption({
321
+ key: `loaded-option-${digg(loadedOption.value)}`,
322
+ loadedOption
323
+ })
315
324
  )}
316
325
  {loadedOptions?.length === 0 &&
317
326
  <div className="haya-select-no-options-container">
@@ -326,26 +335,91 @@ export default class CustomSelect extends React.PureComponent {
326
335
  e.preventDefault()
327
336
  e.stopPropagation()
328
337
 
329
- const {onChange} = this.props
338
+ const {onChange, toggleOptions} = this.props
330
339
  const {multiple} = digs(this.props, "multiple")
331
340
 
332
- this.setState((prevState) => {
333
- const existingOption = prevState.currentOptions.find((currentOption) => currentOption.value == loadedOption.value)
341
+ this.setState(
342
+ (prevState) => {
343
+ const existingOption = prevState.currentOptions.find((currentOption) => currentOption.value == loadedOption.value)
344
+ const newState = {}
345
+ const {toggled} = digs(prevState, "toggled")
346
+ const newToggled = {...toggled}
347
+
348
+ if (existingOption) {
349
+ if (toggleOptions) {
350
+ const currentIndex = digg(toggled, loadedOption.value)
351
+
352
+ if (currentIndex >= (toggleOptions.length - 1)) {
353
+ delete newToggled[loadedOption.value]
354
+
355
+ newState.currentOptions = prevState.currentOptions.filter((currentOption) => currentOption.value != loadedOption.value)
356
+ } else {
357
+ newToggled[loadedOption.value] = toggled[loadedOption.value] + 1
358
+ }
359
+
360
+ newState.toggled = newToggled
361
+ } else {
362
+ newState.currentOptions = prevState.currentOptions.filter((currentOption) => currentOption.value != loadedOption.value)
363
+ }
364
+ } else {
365
+ if (toggleOptions) {
366
+ newToggled[loadedOption.value] = 0
367
+ newState.toggled = newToggled
368
+ }
334
369
 
335
- if (existingOption) {
336
- return {
337
- currentOptions: prevState.currentOptions.filter((currentOption) => currentOption.value != loadedOption.value)
370
+ if (multiple || toggleOptions) {
371
+ newState.currentOptions = prevState.currentOptions.concat([loadedOption])
372
+ } else {
373
+ newState.currentOptions = [loadedOption]
374
+ }
338
375
  }
339
- } else {
340
- if (multiple) {
341
- return {currentOptions: prevState.currentOptions.concat([loadedOption])}
342
- } else {
343
- return {currentOptions: [loadedOption]}
376
+
377
+ return newState
378
+ },
379
+ () => {
380
+ if (onChange) {
381
+ const toggles = {}
382
+
383
+ for(const toggleKey in this.state.toggled) {
384
+ const toggleValue = digg(this, "state", "toggled", toggleKey)
385
+ const toggleOption = digg(this, "props", "toggleOptions", toggleValue)
386
+
387
+ toggles[toggleKey] = toggleOption
388
+ }
389
+
390
+ onChange({
391
+ options: this.state.currentOptions,
392
+ toggles
393
+ })
344
394
  }
345
395
  }
346
- })
396
+ )
347
397
 
348
398
  if (!multiple) this.closeOptions()
349
- if (onChange) onChange(loadedOption)
399
+ }
400
+
401
+ presentOption = (currentValue) => {
402
+ const {toggleOptions} = this.props
403
+ const {toggled} = digs(this.state, "toggled")
404
+
405
+ return (
406
+ <div
407
+ className="haya-select-option-presentation"
408
+ data-toggle-icon={toggleOptions[toggled[currentValue.value]]?.icon}
409
+ data-toggle-value={toggleOptions[toggled[currentValue.value]]?.value}
410
+ data-value={currentValue.value}
411
+ >
412
+ {toggleOptions && !(currentValue.value in toggled) &&
413
+ <i className="fa fa-fw" />
414
+ }
415
+ {toggleOptions && (currentValue.value in toggled) &&
416
+ <i className={`fa fa-fw fa-${toggleOptions[toggled[currentValue.value]].icon}`} />
417
+ }
418
+ {currentValue.text}
419
+ {("html" in currentValue) &&
420
+ <div dangerouslySetInnerHTML={{__html: digg(currentValue, "html")}} />
421
+ }
422
+ </div>
423
+ )
350
424
  }
351
425
  }