treeselectjs 0.2.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/src/list.js ADDED
@@ -0,0 +1,629 @@
1
+ import svg from './svgIcons.js'
2
+
3
+ const getFlatOptons = (options, openLevel, groupId = 0, level = 0) => {
4
+ return options.reduce((acc, curr) => {
5
+ const isGroup = !!curr.children?.length
6
+ const isClosed = level >= openLevel && isGroup
7
+ const hidden = level > openLevel
8
+ acc.push({ id: curr.value, name: curr.name, childOf: groupId, isGroup, checked: false, level, isClosed, hidden })
9
+
10
+ if (isGroup) {
11
+ const children = getFlatOptons(curr.children, openLevel, curr.value, level + 1)
12
+ acc.push(...children)
13
+ }
14
+
15
+ return acc
16
+ }, [])
17
+ }
18
+
19
+ const checkAllChildrenInputs = ({ id, checked }, flatOptions) => {
20
+ flatOptions.forEach(option => {
21
+ if (option.childOf === id) {
22
+ option.checked = checked
23
+
24
+ if (option.isGroup) {
25
+ checkAllChildrenInputs(option, flatOptions)
26
+ }
27
+ }
28
+ })
29
+ }
30
+
31
+ const checkAllParentInputs = (childOf, flatOptions) => {
32
+ const parent = flatOptions.find(option => option.id === childOf)
33
+ const allParentChildren = flatOptions.filter(option => option.childOf === parent.id)
34
+
35
+ const isAllChecked = allParentChildren.every(option => option.checked)
36
+ const isPartialChecked = allParentChildren.some(option => option.isPartialChecked || option.checked) && !isAllChecked
37
+ const isUnchecked = !isAllChecked && !isPartialChecked
38
+
39
+ if (isAllChecked) {
40
+ parent.checked = true
41
+ parent.isPartialChecked = false
42
+ }
43
+
44
+ if (isPartialChecked) {
45
+ parent.checked = false
46
+ parent.isPartialChecked = true
47
+ }
48
+
49
+ if (isUnchecked) {
50
+ parent.checked = false
51
+ parent.isPartialChecked = false
52
+ }
53
+
54
+ if (parent.childOf) {
55
+ checkAllParentInputs(parent.childOf, flatOptions)
56
+ }
57
+ }
58
+
59
+ const checkInput = ({ id, isGroup, childOf, checked }, flatOptions) => {
60
+ if (isGroup) {
61
+ checkAllChildrenInputs({ id, checked }, flatOptions)
62
+ }
63
+
64
+ if (childOf) {
65
+ checkAllParentInputs(childOf, flatOptions)
66
+ }
67
+ }
68
+
69
+ const updateValue = (newValue, flatOptions, srcElement) => {
70
+ flatOptions.forEach(option => option.checked = false)
71
+ const toCheck = flatOptions.filter(option => newValue.includes(option.id))
72
+ toCheck.forEach(option => {
73
+ option.checked = true
74
+ option.isPartialChecked = false
75
+ checkInput(option, flatOptions)
76
+ })
77
+ updateDOM(flatOptions, srcElement)
78
+ }
79
+
80
+ const hideShowChildren = (flattedOptions, { id, isClosed }) => {
81
+ const allChildrenOptions = flattedOptions.filter(fo => fo.childOf === id)
82
+
83
+ allChildrenOptions.forEach(option => {
84
+ option.hidden = isClosed
85
+
86
+ if (option.isGroup && !option.isClosed) {
87
+ hideShowChildren(flattedOptions, { id: option.id, isClosed })
88
+ }
89
+ })
90
+ }
91
+
92
+ const updateDOM = (flatOptions, srcElement) => {
93
+ flatOptions.forEach(option => {
94
+ const input = srcElement.querySelector(`[input-id="${option.id}"]`)
95
+ const listItem = getListItemByCheckbox(input)
96
+ input.checked = option.checked
97
+
98
+ if (option.checked) {
99
+ listItem.classList.add('treeselect-list__item--checked')
100
+ } else {
101
+ listItem.classList.remove('treeselect-list__item--checked')
102
+ }
103
+
104
+ if (option.isPartialChecked) {
105
+ listItem.classList.add('treeselect-list__item--partial-checked')
106
+ } else {
107
+ listItem.classList.remove('treeselect-list__item--partial-checked')
108
+ }
109
+
110
+ if (option.isGroup) {
111
+ const icon = listItem.querySelector('.treeselect-list__item-icon')
112
+
113
+ if (option.isClosed) {
114
+ listItem.classList.add('treeselect-list__item--closed')
115
+ icon.innerHTML = svg.arrowRight
116
+ } else {
117
+ listItem.classList.remove('treeselect-list__item--closed')
118
+ icon.innerHTML = svg.arrowDown
119
+ }
120
+ }
121
+
122
+ if (option.hidden) {
123
+ listItem.classList.add('treeselect-list__item--hidden')
124
+ } else {
125
+ listItem.classList.remove('treeselect-list__item--hidden')
126
+ }
127
+
128
+ if (!option.childOf && !option.isGroup) {
129
+ listItem.style.paddingLeft = `${20}px`
130
+ } else {
131
+ listItem.style.paddingLeft = option.isGroup ? `${option.level * 40}px` : `${option.level * 60}px`
132
+ }
133
+
134
+ updateCheckboxClasses(option, input)
135
+ })
136
+
137
+ const isNotEmpty = flatOptions.some(option => !option.hidden)
138
+ const emptyList = srcElement.querySelector('.treeselect-list__empty')
139
+
140
+ if(isNotEmpty) {
141
+ emptyList.classList.add('treeselect-list__empty--hidden')
142
+ } else {
143
+ emptyList.classList.remove('treeselect-list__empty--hidden')
144
+ }
145
+ }
146
+
147
+ // Updates classes
148
+ const updateCheckboxClasses = (option, input) => {
149
+ const inputContainer = input.parentNode
150
+ const icon = inputContainer.querySelector('.treeselect-list__item-checkbox-icon')
151
+
152
+ if (option.checked) {
153
+ icon.innerHTML = svg.check
154
+ } else if (option.isPartialChecked) {
155
+ icon.innerHTML = svg.partialCheck
156
+ } else {
157
+ icon.innerHTML = ''
158
+ }
159
+ }
160
+
161
+ const getAllFlattedChildren = (childOf, flattedOption) => {
162
+ return flattedOption.reduce((acc, curr) => {
163
+ if (curr.childOf === childOf) {
164
+ acc.push(curr)
165
+
166
+ if (curr.isGroup) {
167
+ acc.push(...getAllFlattedChildren(curr.id, flattedOption))
168
+ }
169
+ }
170
+
171
+ return acc
172
+ }, [])
173
+ }
174
+
175
+ const getAllFlattendParents = (childOf, flatOptions) => {
176
+ return flatOptions.reduce((acc, curr) => {
177
+ if (curr.id === childOf) {
178
+ acc.push(curr)
179
+
180
+ if (curr.childOf) {
181
+ acc.push(...getAllFlattendParents(curr.childOf, flatOptions))
182
+ }
183
+ }
184
+
185
+ return acc
186
+ }, [])
187
+ }
188
+
189
+ const getGroupedValues = (flatOptions) => {
190
+ const { onlyGroupsIds, allItems } = flatOptions.reduce((acc, curr) => {
191
+ if (!curr.checked) {
192
+ return acc
193
+ }
194
+
195
+ if (curr.isGroup) {
196
+ acc.onlyGroupsIds.push(curr.id)
197
+ }
198
+
199
+ acc.allItems.push(curr)
200
+
201
+ return acc
202
+ }, {
203
+ onlyGroupsIds: [],
204
+ allItems: []
205
+ })
206
+
207
+ return allItems.filter(item => !onlyGroupsIds.includes(item.childOf))
208
+ }
209
+
210
+ const getCheckedValues = (flatOptions) => {
211
+ return flatOptions.filter(option => option.checked && !option.isGroup)
212
+ }
213
+
214
+ const getListItemByCheckbox = (checkbox) => {
215
+ const checkboxContainer = checkbox.parentNode
216
+ const listItem = checkboxContainer.parentNode
217
+
218
+ return listItem
219
+ }
220
+
221
+ class TreeselectList {
222
+ #lastFocusedItem = null
223
+ #isMouseActionsAvailable = true
224
+
225
+ constructor({
226
+ options,
227
+ value,
228
+ openLevel,
229
+ listSlotHtmlComponent,
230
+ emptyText
231
+ }) {
232
+ this.options = options
233
+ this.value = value
234
+ this.searchText = ''
235
+ this.openLevel = openLevel ?? 0
236
+ this.listSlotHtmlComponent = listSlotHtmlComponent
237
+ this.emptyText = emptyText ?? 'No results found...'
238
+
239
+ this.flattedOptions = getFlatOptons(this.options, this.openLevel)
240
+ this.flattedOptionsBeforeSearch = this.flattedOptions
241
+ this.selectedNodes = { ids: [], groupedIds: [] }
242
+ this.srcElement = this.#createList()
243
+
244
+ this.updateValue(this.value)
245
+ }
246
+
247
+ // Public methods
248
+ updateValue (value) {
249
+ updateValue(value, this.flattedOptions, this.srcElement)
250
+ this.#updateSelectedNodes()
251
+ }
252
+
253
+ updateSearchValue (searchText) {
254
+ const isStartOfSearching = this.searchText === '' && searchText !== ''
255
+ this.searchText = searchText
256
+
257
+ if (isStartOfSearching) {
258
+ this.flattedOptionsBeforeSearch = JSON.parse(JSON.stringify(this.flattedOptions))
259
+ }
260
+
261
+ if (this.searchText === '') {
262
+ // This loop need to save a isClose state before searching
263
+ this.flattedOptions = this.flattedOptionsBeforeSearch.map(option => {
264
+ const newOptionData = this.flattedOptions.find(newOption => newOption.id === option.id)
265
+ newOptionData.isClosed = option.isClosed
266
+ newOptionData.hidden = option.hidden
267
+
268
+ return newOptionData
269
+ })
270
+
271
+ this.flattedOptionsBeforeSearch = []
272
+ updateDOM(this.flattedOptions, this.srcElement)
273
+ this.focusFirstListElement()
274
+
275
+ return
276
+ }
277
+
278
+ const allOptions = this.flattedOptions.reduce((acc, curr) => {
279
+ const isSerched = curr.name.toLowerCase().includes(searchText.toLowerCase())
280
+
281
+ if (isSerched) {
282
+ acc.push(curr)
283
+
284
+ if (curr.isGroup) {
285
+ const flattedChildren = getAllFlattedChildren(curr.id, this.flattedOptions)
286
+ acc.push(...flattedChildren)
287
+ }
288
+
289
+ if (curr.childOf) {
290
+ const flattedParents = getAllFlattendParents(curr.childOf, this.flattedOptions)
291
+ acc.push(...flattedParents)
292
+ }
293
+ }
294
+
295
+ return acc
296
+ }, [])
297
+ this.flattedOptions.forEach(option => {
298
+ const isVisible = allOptions.some(ao => ao.id === option.id)
299
+
300
+ if (isVisible) {
301
+ if (option.isGroup) {
302
+ option.isClosed = false
303
+ hideShowChildren(this.flattedOptions, option)
304
+ }
305
+
306
+ option.hidden = false
307
+ } else {
308
+ option.hidden = true
309
+ }
310
+ })
311
+ updateDOM(this.flattedOptions, this.srcElement)
312
+ this.focusFirstListElement()
313
+ }
314
+
315
+ callKeyAction (key) {
316
+ this.#isMouseActionsAvailable = false
317
+ const itemFocused = this.srcElement.querySelector('.treeselect-list__item--focused')
318
+
319
+ if (key === 'Enter' && itemFocused) {
320
+ itemFocused.dispatchEvent(new Event('click'))
321
+ }
322
+
323
+ if (key === 'ArrowLeft' || key === 'ArrowRight') {
324
+ if (!itemFocused) {
325
+ return
326
+ }
327
+
328
+ const checkbox = itemFocused.querySelector('.treeselect-list__item-checkbox')
329
+ const inputId = checkbox.getAttribute('input-id')
330
+ const option = this.flattedOptions.find(option => option.id === inputId)
331
+ const arrow = itemFocused.querySelector('.treeselect-list__item-icon')
332
+
333
+ if (key === 'ArrowLeft' && !option.isClosed) {
334
+ arrow.dispatchEvent(new Event('click'))
335
+ }
336
+
337
+ if (key === 'ArrowRight' && option.isClosed) {
338
+ arrow.dispatchEvent(new Event('click'))
339
+ }
340
+ }
341
+
342
+ if (key === 'ArrowDown' || key === 'ArrowUp') {
343
+ const allCheckboxes = Array.from(this.srcElement.querySelectorAll('.treeselect-list__item-checkbox'))
344
+ .filter(checkbox => window.getComputedStyle(getListItemByCheckbox(checkbox)).display !== 'none')
345
+
346
+ if (!allCheckboxes.length) {
347
+ return
348
+ }
349
+
350
+ if (!itemFocused) {
351
+ const firstNode = getListItemByCheckbox(allCheckboxes[0])
352
+ firstNode.classList.add('treeselect-list__item--focused')
353
+ } else {
354
+ const focusedCheckboxIndex = allCheckboxes.findIndex(el => getListItemByCheckbox(el).classList.contains('treeselect-list__item--focused'))
355
+ const focusedNode = getListItemByCheckbox(allCheckboxes[focusedCheckboxIndex])
356
+ focusedNode.classList.remove('treeselect-list__item--focused')
357
+
358
+ const nextNodeIndex = key === 'ArrowDown' ? focusedCheckboxIndex + 1 : focusedCheckboxIndex - 1
359
+ const defaultNodeIndex = key === 'ArrowDown' ? 0 : allCheckboxes.length - 1
360
+ const nextCheckbox = allCheckboxes[nextNodeIndex] ?? allCheckboxes[defaultNodeIndex]
361
+ const isDefaultIndex = !allCheckboxes[nextNodeIndex]
362
+ const nextNodeToFocus = getListItemByCheckbox(nextCheckbox)
363
+ nextNodeToFocus.classList.add('treeselect-list__item--focused')
364
+
365
+ const listCoord = this.srcElement.getBoundingClientRect()
366
+ const nextCoord = nextNodeToFocus.getBoundingClientRect()
367
+
368
+ if (isDefaultIndex && key === 'ArrowDown') {
369
+ this.srcElement.scroll(0, 0)
370
+
371
+ return
372
+ }
373
+
374
+ if (isDefaultIndex && key === 'ArrowUp') {
375
+ this.srcElement.scroll(0, this.srcElement.scrollHeight)
376
+
377
+ return
378
+ }
379
+
380
+ if (listCoord.y + listCoord.height < nextCoord.y + nextCoord.height) {
381
+ this.srcElement.scroll(0, this.srcElement.scrollTop + nextCoord.height)
382
+
383
+ return
384
+ }
385
+
386
+ if (listCoord.y > nextCoord.y) {
387
+ this.srcElement.scroll(0, this.srcElement.scrollTop - nextCoord.height)
388
+
389
+ return
390
+ }
391
+ }
392
+ }
393
+ }
394
+
395
+ focusFirstListElement () {
396
+ const focusedCalss = 'treeselect-list__item--focused'
397
+ const itemFocused = this.srcElement.querySelector(`.${focusedCalss}`)
398
+ const allCheckboxes = Array.from(this.srcElement.querySelectorAll('.treeselect-list__item-checkbox'))
399
+ .filter(checkbox => window.getComputedStyle(getListItemByCheckbox(checkbox)).display !== 'none')
400
+
401
+ if (!allCheckboxes.length) {
402
+ return
403
+ }
404
+
405
+ if (itemFocused) {
406
+ itemFocused.classList.remove(focusedCalss)
407
+ }
408
+
409
+ const firstItem = getListItemByCheckbox(allCheckboxes[0])
410
+ firstItem.classList.add(focusedCalss)
411
+ }
412
+
413
+ // Private methods
414
+ #createList () {
415
+ const elementsToCreate = []
416
+
417
+ const list = document.createElement('div')
418
+ list.classList.add('treeselect-list')
419
+ const htmlTreeList = this.#getListHTML(this.options)
420
+ elementsToCreate.push(...htmlTreeList)
421
+
422
+
423
+ if (this.listSlotHtmlComponent) {
424
+ const slot = document.createElement('div')
425
+ slot.classList.add('treeselect-list__slot')
426
+ slot.appendChild(this.listSlotHtmlComponent)
427
+ elementsToCreate.push(slot)
428
+ }
429
+
430
+ const emptyList = this.#createEmptyList()
431
+ elementsToCreate.push(emptyList)
432
+
433
+ list.addEventListener('mouseout', (e) => {
434
+ e.stopPropagation()
435
+
436
+ if (this.#lastFocusedItem && this.#isMouseActionsAvailable) {
437
+ this.#lastFocusedItem.classList.add('treeselect-list__item--focused')
438
+ }
439
+ })
440
+ list.addEventListener('mousemove', () => {
441
+ this.#isMouseActionsAvailable = true
442
+ })
443
+
444
+ list.append(...elementsToCreate)
445
+
446
+ return list
447
+ }
448
+
449
+ #getListHTML (options) {
450
+ return options.reduce((acc, option) => {
451
+ if (option.children?.length) {
452
+ const groupContainer = this.#createGroupContainer(option)
453
+ const innerGroupsAndElements = this.#getListHTML(option.children)
454
+
455
+ groupContainer.append(...innerGroupsAndElements)
456
+ acc.push(groupContainer)
457
+
458
+ return acc
459
+ }
460
+
461
+ const itemGroupElement = this.#createGroupItem(option, false)
462
+ acc.push(itemGroupElement)
463
+
464
+ return acc
465
+ }, [])
466
+ }
467
+
468
+ #createGroupContainer (option) {
469
+ const groupContainerElement = document.createElement('div')
470
+ groupContainerElement.setAttribute('group-container-id', option.value)
471
+ groupContainerElement.classList.add('treeselect-list__group-container')
472
+
473
+ const groupItemElement = this.#createGroupItem(option, true)
474
+ groupContainerElement.appendChild(groupItemElement)
475
+
476
+ return groupContainerElement
477
+ }
478
+
479
+ #createGroupItem (option, isGroup) {
480
+ const itemElement = document.createElement('div')
481
+ itemElement.setAttribute('tabindex', '-1')
482
+ itemElement.setAttribute('title', option.name)
483
+ itemElement.classList.add('treeselect-list__item')
484
+
485
+ if (isGroup) {
486
+ const arrow = this.#createArrow()
487
+ itemElement.appendChild(arrow)
488
+ }
489
+
490
+ itemElement.addEventListener('mouseover', () => {
491
+ if (this.#isMouseActionsAvailable) {
492
+ this.#groupMouseAction(true, itemElement)
493
+ }
494
+ }, true)
495
+ itemElement.addEventListener('mouseout', () => {
496
+ if (this.#isMouseActionsAvailable) {
497
+ this.#groupMouseAction(false, itemElement)
498
+ this.#lastFocusedItem = itemElement
499
+ }
500
+ }, true)
501
+ itemElement.addEventListener('click', (e) => {
502
+ e.stopPropagation()
503
+ const checkbox = e.target.querySelector('.treeselect-list__item-checkbox')
504
+ checkbox.checked = !checkbox.checked
505
+ this.#checkboxClickEvent(checkbox, option)
506
+ })
507
+
508
+ const checkbox = this.#createCheckbox(option)
509
+ const label = this.#createCheckboxLabel(option)
510
+ itemElement.append(checkbox, label)
511
+
512
+ return itemElement
513
+ }
514
+
515
+ #createArrow () {
516
+ const arrow = document.createElement('span')
517
+ arrow.setAttribute('tabindex', '-1')
518
+ arrow.classList.add('treeselect-list__item-icon')
519
+ arrow.innerHTML = svg.arrowDown
520
+
521
+ arrow.addEventListener('click', (e) => {
522
+ e.stopPropagation()
523
+ this.#arrowClickEvent(e)
524
+ })
525
+
526
+ return arrow
527
+ }
528
+
529
+ #createCheckbox (option) {
530
+ const checkboxContainer = document.createElement('div')
531
+ checkboxContainer.classList.add('treeselect-list__item-checkbox-container')
532
+ const ico = document.createElement('span')
533
+ ico.classList.add('treeselect-list__item-checkbox-icon')
534
+ ico.innerHTML = ''
535
+
536
+ const checkbox = document.createElement('input')
537
+ checkbox.setAttribute('tabindex', '-1')
538
+ checkbox.setAttribute('type', `checkbox`)
539
+ checkbox.setAttribute('input-id', option.value)
540
+ checkbox.classList.add('treeselect-list__item-checkbox')
541
+
542
+ checkboxContainer.append(ico, checkbox)
543
+
544
+ return checkboxContainer
545
+ }
546
+
547
+ #createCheckboxLabel (option) {
548
+ const label = document.createElement('label')
549
+ label.innerHTML = option.name
550
+ label.classList.add('treeselect-list__item-label')
551
+
552
+ return label
553
+ }
554
+
555
+ #createEmptyList () {
556
+ const emptyList = document.createElement('div')
557
+ emptyList.classList.add('treeselect-list__empty')
558
+ emptyList.setAttribute('title', this.emptyText)
559
+
560
+ const icon = document.createElement('span')
561
+ icon.classList.add('treeselect-list__empty-icon')
562
+ icon.innerHTML = svg.attention
563
+
564
+ const text = document.createElement('span')
565
+ text.classList.add('treeselect-list__empty-text')
566
+ text.innerHTML = this.emptyText
567
+
568
+ emptyList.append(icon, text)
569
+
570
+ return emptyList
571
+ }
572
+
573
+ // Actions
574
+ #checkboxClickEvent(target, option) {
575
+ const flattedOption = this.flattedOptions.find(fo => fo.id === option.value)
576
+ flattedOption.checked = target.checked
577
+ flattedOption.isPartialChecked = false
578
+ checkInput(flattedOption, this.flattedOptions)
579
+ updateDOM(this.flattedOptions, this.srcElement)
580
+
581
+ this.#emitInput()
582
+ }
583
+
584
+ #arrowClickEvent (e) {
585
+ const input = e.target.parentNode.querySelector('[input-id]')
586
+ const id = input.getAttribute('input-id')
587
+ const flattedOption = this.flattedOptions.find(fo => fo.id === id)
588
+ flattedOption.isClosed = !flattedOption.isClosed
589
+ hideShowChildren(this.flattedOptions, flattedOption)
590
+ updateDOM(this.flattedOptions, this.srcElement)
591
+
592
+ this.#emitArrrowClick()
593
+ }
594
+
595
+ #groupMouseAction (isMouseOver, itemElement) {
596
+ const focusedClassName = 'treeselect-list__item--focused'
597
+
598
+ if (isMouseOver) {
599
+ const itemsFocused = Array.from(this.srcElement.querySelectorAll(`.${focusedClassName}`))
600
+
601
+ if (itemsFocused.length) {
602
+ itemsFocused.forEach(el => el.classList.remove(focusedClassName))
603
+ }
604
+
605
+ itemElement.classList.add(focusedClassName)
606
+ } else {
607
+ itemElement.classList.remove(focusedClassName)
608
+ }
609
+ }
610
+
611
+ #updateSelectedNodes () {
612
+ this.selectedNodes = {
613
+ ids: getCheckedValues(this.flattedOptions),
614
+ groupedIds: getGroupedValues(this.flattedOptions)
615
+ }
616
+ }
617
+
618
+ // Emits
619
+ #emitArrrowClick () {
620
+ this.srcElement.dispatchEvent(new CustomEvent('arrow-click'))
621
+ }
622
+
623
+ #emitInput () {
624
+ this.#updateSelectedNodes()
625
+ this.srcElement.dispatchEvent(new CustomEvent('input', { detail: this.selectedNodes}))
626
+ }
627
+ }
628
+
629
+ export default TreeselectList
@@ -0,0 +1,10 @@
1
+ export default {
2
+ arrowUp: '<svg xmlns="http://www.w3.org/2000/svg" width="15" height="15" viewBox="0 0 25 25" fill="none" stroke="#000000" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M18 15l-6-6-6 6"/></svg>',
3
+ arrowDown: '<svg xmlns="http://www.w3.org/2000/svg" width="15" height="15" viewBox="0 0 25 25" fill="none" stroke="#000000" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M6 9l6 6 6-6"/></svg>',
4
+ arrowRight: '<svg xmlns="http://www.w3.org/2000/svg" width="15" height="15" viewBox="0 0 25 25" fill="none" stroke="#000000" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M9 18l6-6-6-6"/></svg>',
5
+ attention: '<svg xmlns="http://www.w3.org/2000/svg" width="15" height="15" viewBox="0 0 25 25" fill="none" stroke="#000000" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M10.29 3.86L1.82 18a2 2 0 0 0 1.71 3h16.94a2 2 0 0 0 1.71-3L13.71 3.86a2 2 0 0 0-3.42 0z"></path><line x1="12" y1="9" x2="12" y2="13"></line><line x1="12" y1="17" x2="12.01" y2="17"></line></svg>',
6
+ clear: '<svg xmlns="http://www.w3.org/2000/svg" width="15" height="15" viewBox="0 0 25 25" fill="none" stroke="#000000" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><circle cx="12" cy="12" r="10"></circle><line x1="15" y1="9" x2="9" y2="15"></line><line x1="9" y1="9" x2="15" y2="15"></line></svg>',
7
+ cross: '<svg xmlns="http://www.w3.org/2000/svg" width="15" height="15" viewBox="0 0 25 25" fill="none" stroke="#000000" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><line x1="18" y1="6" x2="6" y2="18"></line><line x1="6" y1="6" x2="18" y2="18"></line></svg>',
8
+ check: '<svg xmlns="http://www.w3.org/2000/svg" width="15" height="15" viewBox="0 0 25 25" fill="none" stroke="#000000" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><polyline points="20 6 9 17 4 12"></polyline></svg>',
9
+ partialCheck: '<svg xmlns="http://www.w3.org/2000/svg" width="15" height="15" viewBox="0 0 25 25" fill="none" stroke="#000000" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><line x1="5" y1="12" x2="19" y2="12"></line></svg>'
10
+ }
@@ -0,0 +1,67 @@
1
+ @import './input.css';
2
+ @import './list.css';
3
+
4
+ .treeselect {
5
+ width: 100%;
6
+ position: relative;
7
+ box-sizing: border-box;
8
+ }
9
+
10
+ .treeselect--disabled {
11
+ pointer-events: none;
12
+ }
13
+
14
+ .treeselect-list {
15
+ position: absolute;
16
+ left: 0;
17
+ border-radius: 4px;
18
+ box-sizing: border-box;
19
+ }
20
+
21
+ .treeselect .treeselect-list {
22
+ position: absolute;
23
+ }
24
+
25
+ .treeselect-input--focused {
26
+ border-color: #101010;
27
+ }
28
+
29
+ .treeselect-input--opened.treeselect-input--top {
30
+ border-top-color: transparent;
31
+ border-top-left-radius: 0;
32
+ border-top-right-radius: 0;
33
+ }
34
+
35
+ .treeselect-input--opened.treeselect-input--bottom {
36
+ border-bottom-color: transparent;
37
+ border-bottom-left-radius: 0;
38
+ border-bottom-right-radius: 0;
39
+ }
40
+
41
+ .treeselect-list--focused {
42
+ border-color: #101010;
43
+ }
44
+
45
+ .treeselect-list--top,
46
+ .treeselect-list--top-to-body {
47
+ border-bottom-color: #d7dde4;
48
+ border-bottom-left-radius: 0;
49
+ border-bottom-right-radius: 0;
50
+ }
51
+
52
+ .treeselect-list--bottom,
53
+ .treeselect-list--bottom-to-body {
54
+ border-top-color: gainsboro;
55
+ border-top-left-radius: 0;
56
+ border-top-right-radius: 0;
57
+ }
58
+
59
+ .treeselect-list--top {
60
+ left: 0;
61
+ bottom: 100%;
62
+ }
63
+
64
+ .treeselect-list--bottom {
65
+ left: 0;
66
+ top: 100%;
67
+ }