@coreui/coreui 5.5.0 → 5.6.1
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 +1 -1
- package/README.md +5 -3
- package/dist/css/coreui-grid.css +2 -2
- package/dist/css/coreui-grid.css.map +1 -1
- package/dist/css/coreui-grid.min.css +2 -2
- package/dist/css/coreui-grid.min.css.map +1 -1
- package/dist/css/coreui-grid.rtl.css +2 -2
- package/dist/css/coreui-grid.rtl.css.map +1 -1
- package/dist/css/coreui-grid.rtl.min.css +2 -2
- package/dist/css/coreui-grid.rtl.min.css.map +1 -1
- package/dist/css/coreui-reboot.css +11 -2
- package/dist/css/coreui-reboot.css.map +1 -1
- package/dist/css/coreui-reboot.min.css +3 -3
- package/dist/css/coreui-reboot.min.css.map +1 -1
- package/dist/css/coreui-reboot.rtl.css +11 -2
- package/dist/css/coreui-reboot.rtl.css.map +1 -1
- package/dist/css/coreui-reboot.rtl.min.css +3 -3
- package/dist/css/coreui-reboot.rtl.min.css.map +1 -1
- package/dist/css/coreui-utilities.css +11 -2
- package/dist/css/coreui-utilities.css.map +1 -1
- package/dist/css/coreui-utilities.min.css +3 -3
- package/dist/css/coreui-utilities.min.css.map +1 -1
- package/dist/css/coreui-utilities.rtl.css +11 -2
- package/dist/css/coreui-utilities.rtl.css.map +1 -1
- package/dist/css/coreui-utilities.rtl.min.css +3 -3
- package/dist/css/coreui-utilities.rtl.min.css.map +1 -1
- package/dist/css/coreui.css +337 -2
- package/dist/css/coreui.css.map +1 -1
- package/dist/css/coreui.min.css +3 -3
- package/dist/css/coreui.min.css.map +1 -1
- package/dist/css/coreui.rtl.css +332 -2
- package/dist/css/coreui.rtl.css.map +1 -1
- package/dist/css/coreui.rtl.min.css +3 -3
- package/dist/css/coreui.rtl.min.css.map +1 -1
- package/dist/css/themes/bootstrap/bootstrap.css +337 -2
- package/dist/css/themes/bootstrap/bootstrap.css.map +1 -1
- package/dist/css/themes/bootstrap/bootstrap.min.css +3 -3
- package/dist/css/themes/bootstrap/bootstrap.min.css.map +1 -1
- package/dist/css/themes/bootstrap/bootstrap.rtl.css +332 -2
- package/dist/css/themes/bootstrap/bootstrap.rtl.css.map +1 -1
- package/dist/css/themes/bootstrap/bootstrap.rtl.min.css +3 -3
- package/dist/css/themes/bootstrap/bootstrap.rtl.min.css.map +1 -1
- package/dist/js/bootstrap.bundle.js +872 -60
- package/dist/js/bootstrap.bundle.js.map +1 -1
- package/dist/js/bootstrap.bundle.min.js +3 -3
- package/dist/js/bootstrap.bundle.min.js.map +1 -1
- package/dist/js/bootstrap.esm.js +871 -53
- package/dist/js/bootstrap.esm.js.map +1 -1
- package/dist/js/bootstrap.esm.min.js +3 -3
- package/dist/js/bootstrap.esm.min.js.map +1 -1
- package/dist/js/bootstrap.js +872 -52
- package/dist/js/bootstrap.js.map +1 -1
- package/dist/js/bootstrap.min.js +3 -3
- package/dist/js/bootstrap.min.js.map +1 -1
- package/dist/js/coreui.bundle.js +872 -60
- package/dist/js/coreui.bundle.js.map +1 -1
- package/dist/js/coreui.bundle.min.js +3 -3
- package/dist/js/coreui.bundle.min.js.map +1 -1
- package/dist/js/coreui.esm.js +871 -53
- package/dist/js/coreui.esm.js.map +1 -1
- package/dist/js/coreui.esm.min.js +3 -3
- package/dist/js/coreui.esm.min.js.map +1 -1
- package/dist/js/coreui.js +872 -52
- package/dist/js/coreui.js.map +1 -1
- package/dist/js/coreui.min.js +3 -3
- package/dist/js/coreui.min.js.map +1 -1
- package/js/dist/alert.js +2 -2
- package/js/dist/base-component.js +3 -3
- package/js/dist/base-component.js.map +1 -1
- package/js/dist/button.js +2 -2
- package/js/dist/carousel.js +2 -2
- package/js/dist/chip-input.js +526 -0
- package/js/dist/chip-input.js.map +1 -0
- package/js/dist/chip.js +322 -0
- package/js/dist/chip.js.map +1 -0
- package/js/dist/collapse.js +2 -2
- package/js/dist/dom/data.js +2 -2
- package/js/dist/dom/event-handler.js +2 -2
- package/js/dist/dom/manipulator.js +2 -2
- package/js/dist/dom/selector-engine.js +2 -2
- package/js/dist/dropdown.js +2 -2
- package/js/dist/modal.js +2 -2
- package/js/dist/navigation.js +2 -2
- package/js/dist/offcanvas.js +2 -2
- package/js/dist/popover.js +2 -2
- package/js/dist/scrollspy.js +2 -2
- package/js/dist/sidebar.js +2 -2
- package/js/dist/tab.js +2 -2
- package/js/dist/toast.js +2 -2
- package/js/dist/tooltip.js +2 -2
- package/js/dist/util/backdrop.js +2 -2
- package/js/dist/util/component-functions.js +2 -2
- package/js/dist/util/config.js +2 -2
- package/js/dist/util/focustrap.js +2 -2
- package/js/dist/util/index.js +2 -2
- package/js/dist/util/sanitizer.js +2 -2
- package/js/dist/util/scrollbar.js +2 -2
- package/js/dist/util/swipe.js +2 -2
- package/js/dist/util/template-factory.js +2 -2
- package/js/index.esm.js +2 -0
- package/js/index.umd.js +4 -0
- package/js/src/base-component.js +1 -1
- package/js/src/chip-input.js +593 -0
- package/js/src/chip.js +365 -0
- package/package.json +22 -22
- package/scss/_banner.scss +2 -2
- package/scss/_chip.import.scss +1 -0
- package/scss/_chip.scss +261 -0
- package/scss/_forms.scss +1 -0
- package/scss/_maps.scss +14 -0
- package/scss/_root.scss +5 -0
- package/scss/coreui.scss +1 -0
- package/scss/forms/_chip-input.import.scss +1 -0
- package/scss/forms/_chip-input.scss +109 -0
- package/scss/mixins/_chip.scss +14 -0
- package/scss/mixins/_focus-ring.scss +9 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
/*!
|
|
2
|
-
* CoreUI focustrap.js v5.
|
|
3
|
-
* Copyright
|
|
2
|
+
* CoreUI focustrap.js v5.6.1 (https://coreui.io)
|
|
3
|
+
* Copyright 2026 The CoreUI Team (https://github.com/orgs/coreui/people)
|
|
4
4
|
* Licensed under MIT (https://github.com/coreui/coreui/blob/main/LICENSE)
|
|
5
5
|
*/
|
|
6
6
|
(function (global, factory) {
|
package/js/dist/util/index.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
/*!
|
|
2
|
-
* CoreUI index.js v5.
|
|
3
|
-
* Copyright
|
|
2
|
+
* CoreUI index.js v5.6.1 (https://coreui.io)
|
|
3
|
+
* Copyright 2026 The CoreUI Team (https://github.com/orgs/coreui/people)
|
|
4
4
|
* Licensed under MIT (https://github.com/coreui/coreui/blob/main/LICENSE)
|
|
5
5
|
*/
|
|
6
6
|
(function (global, factory) {
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
/*!
|
|
2
|
-
* CoreUI sanitizer.js v5.
|
|
3
|
-
* Copyright
|
|
2
|
+
* CoreUI sanitizer.js v5.6.1 (https://coreui.io)
|
|
3
|
+
* Copyright 2026 The CoreUI Team (https://github.com/orgs/coreui/people)
|
|
4
4
|
* Licensed under MIT (https://github.com/coreui/coreui/blob/main/LICENSE)
|
|
5
5
|
*/
|
|
6
6
|
(function (global, factory) {
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
/*!
|
|
2
|
-
* CoreUI scrollbar.js v5.
|
|
3
|
-
* Copyright
|
|
2
|
+
* CoreUI scrollbar.js v5.6.1 (https://coreui.io)
|
|
3
|
+
* Copyright 2026 The CoreUI Team (https://github.com/orgs/coreui/people)
|
|
4
4
|
* Licensed under MIT (https://github.com/coreui/coreui/blob/main/LICENSE)
|
|
5
5
|
*/
|
|
6
6
|
(function (global, factory) {
|
package/js/dist/util/swipe.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
/*!
|
|
2
|
-
* CoreUI swipe.js v5.
|
|
3
|
-
* Copyright
|
|
2
|
+
* CoreUI swipe.js v5.6.1 (https://coreui.io)
|
|
3
|
+
* Copyright 2026 The CoreUI Team (https://github.com/orgs/coreui/people)
|
|
4
4
|
* Licensed under MIT (https://github.com/coreui/coreui/blob/main/LICENSE)
|
|
5
5
|
*/
|
|
6
6
|
(function (global, factory) {
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
/*!
|
|
2
|
-
* CoreUI template-factory.js v5.
|
|
3
|
-
* Copyright
|
|
2
|
+
* CoreUI template-factory.js v5.6.1 (https://coreui.io)
|
|
3
|
+
* Copyright 2026 The CoreUI Team (https://github.com/orgs/coreui/people)
|
|
4
4
|
* Licensed under MIT (https://github.com/coreui/coreui/blob/main/LICENSE)
|
|
5
5
|
*/
|
|
6
6
|
(function (global, factory) {
|
package/js/index.esm.js
CHANGED
|
@@ -8,6 +8,8 @@
|
|
|
8
8
|
export { default as Alert } from './src/alert.js'
|
|
9
9
|
export { default as Button } from './src/button.js'
|
|
10
10
|
export { default as Carousel } from './src/carousel.js'
|
|
11
|
+
export { default as Chip } from './src/chip.js'
|
|
12
|
+
export { default as ChipInput } from './src/chip-input.js'
|
|
11
13
|
export { default as Collapse } from './src/collapse.js'
|
|
12
14
|
export { default as Dropdown } from './src/dropdown.js'
|
|
13
15
|
export { default as Modal } from './src/modal.js'
|
package/js/index.umd.js
CHANGED
|
@@ -8,6 +8,8 @@
|
|
|
8
8
|
import Alert from './src/alert.js'
|
|
9
9
|
import Button from './src/button.js'
|
|
10
10
|
import Carousel from './src/carousel.js'
|
|
11
|
+
import Chip from './src/chip.js'
|
|
12
|
+
import ChipInput from './src/chip-input.js'
|
|
11
13
|
import Collapse from './src/collapse.js'
|
|
12
14
|
import Dropdown from './src/dropdown.js'
|
|
13
15
|
import Modal from './src/modal.js'
|
|
@@ -24,6 +26,8 @@ export default {
|
|
|
24
26
|
Alert,
|
|
25
27
|
Button,
|
|
26
28
|
Carousel,
|
|
29
|
+
Chip,
|
|
30
|
+
ChipInput,
|
|
27
31
|
Collapse,
|
|
28
32
|
Dropdown,
|
|
29
33
|
Modal,
|
package/js/src/base-component.js
CHANGED
|
@@ -0,0 +1,593 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* --------------------------------------------------------------------------
|
|
3
|
+
* CoreUI chip-input.js
|
|
4
|
+
* Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE)
|
|
5
|
+
*
|
|
6
|
+
* This component is a highly modified version of the Bootstrap's chip-input.js
|
|
7
|
+
* Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE)
|
|
8
|
+
* --------------------------------------------------------------------------
|
|
9
|
+
*/
|
|
10
|
+
|
|
11
|
+
import BaseComponent from './base-component.js'
|
|
12
|
+
import Chip from './chip.js'
|
|
13
|
+
import EventHandler from './dom/event-handler.js'
|
|
14
|
+
import SelectorEngine from './dom/selector-engine.js'
|
|
15
|
+
import { getUID } from './util/index.js'
|
|
16
|
+
|
|
17
|
+
/**
|
|
18
|
+
* Constants
|
|
19
|
+
*/
|
|
20
|
+
|
|
21
|
+
const NAME = 'chip-input'
|
|
22
|
+
const DATA_KEY = 'coreui.chip-input'
|
|
23
|
+
const EVENT_KEY = `.${DATA_KEY}`
|
|
24
|
+
const DATA_API_KEY = '.data-api'
|
|
25
|
+
|
|
26
|
+
const EVENT_ADD = `add${EVENT_KEY}`
|
|
27
|
+
const EVENT_REMOVE = `remove${EVENT_KEY}`
|
|
28
|
+
const EVENT_CHANGE = `change${EVENT_KEY}`
|
|
29
|
+
const EVENT_SELECT = `select${EVENT_KEY}`
|
|
30
|
+
const EVENT_INPUT = `input${EVENT_KEY}`
|
|
31
|
+
|
|
32
|
+
const SELECTOR_DATA_CHIP_INPUT = '[data-coreui-chip-input]'
|
|
33
|
+
const SELECTOR_CHIP = '.chip'
|
|
34
|
+
const SELECTOR_CHIP_ACTIVE = `${SELECTOR_CHIP}.active`
|
|
35
|
+
const SELECTOR_CHIP_INPUT_LABEL = '.chip-input-label'
|
|
36
|
+
const SELECTOR_CHIP_REMOVE = '.chip-remove'
|
|
37
|
+
const SELECTOR_FOCUSABLE_ITEMS = '.chip:not(.disabled)'
|
|
38
|
+
|
|
39
|
+
const CLASS_NAME_CHIP = 'chip'
|
|
40
|
+
const CLASS_NAME_DISABLED = 'disabled'
|
|
41
|
+
const CLASS_NAME_CHIP_INPUT_FIELD = 'chip-input-field'
|
|
42
|
+
|
|
43
|
+
const DEFAULT_REMOVE_ICON = '<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 16 16" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round"><line x1="4" y1="4" x2="12" y2="12"/><line x1="12" y1="4" x2="4" y2="12"/></svg>'
|
|
44
|
+
|
|
45
|
+
const Default = {
|
|
46
|
+
chipClassName: null,
|
|
47
|
+
createOnBlur: true,
|
|
48
|
+
disabled: false,
|
|
49
|
+
id: null,
|
|
50
|
+
maxChips: null,
|
|
51
|
+
name: null,
|
|
52
|
+
placeholder: '',
|
|
53
|
+
readonly: false,
|
|
54
|
+
removable: true,
|
|
55
|
+
removeIcon: DEFAULT_REMOVE_ICON,
|
|
56
|
+
selectable: false,
|
|
57
|
+
separator: ','
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
const DefaultType = {
|
|
61
|
+
chipClassName: '(string|function|null)',
|
|
62
|
+
createOnBlur: 'boolean',
|
|
63
|
+
disabled: 'boolean',
|
|
64
|
+
maxChips: '(number|null)',
|
|
65
|
+
id: '(string|null)',
|
|
66
|
+
name: '(string|null)',
|
|
67
|
+
placeholder: 'string',
|
|
68
|
+
readonly: 'boolean',
|
|
69
|
+
removable: 'boolean',
|
|
70
|
+
removeIcon: 'string',
|
|
71
|
+
selectable: 'boolean',
|
|
72
|
+
separator: '(string|null)'
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
/**
|
|
76
|
+
* Class definition
|
|
77
|
+
*/
|
|
78
|
+
|
|
79
|
+
class ChipInput extends BaseComponent {
|
|
80
|
+
constructor(element, config) {
|
|
81
|
+
super(element, config)
|
|
82
|
+
|
|
83
|
+
this._uniqueId = this._config.id ?? getUID(`${this.constructor.NAME}`)
|
|
84
|
+
this._disabled = this._config.disabled || this._element.classList.contains(CLASS_NAME_DISABLED)
|
|
85
|
+
this._readonly = this._config.readonly
|
|
86
|
+
|
|
87
|
+
this._chips = []
|
|
88
|
+
this._input = SelectorEngine.findOne('input', this._element)
|
|
89
|
+
this._hiddenInput = null
|
|
90
|
+
|
|
91
|
+
if (this._input) {
|
|
92
|
+
this._setInputSize()
|
|
93
|
+
} else {
|
|
94
|
+
this._createInput()
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
this._applyInteractionState()
|
|
98
|
+
this._initializeExistingChips()
|
|
99
|
+
this._createHiddenInput()
|
|
100
|
+
this._addEventListeners()
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
// Getters
|
|
104
|
+
static get Default() {
|
|
105
|
+
return Default
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
static get DefaultType() {
|
|
109
|
+
return DefaultType
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
static get NAME() {
|
|
113
|
+
return NAME
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
// Public
|
|
117
|
+
add(value) {
|
|
118
|
+
if (this._disabled || this._readonly) {
|
|
119
|
+
return null
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
const trimmedValue = String(value).trim()
|
|
123
|
+
|
|
124
|
+
if (!trimmedValue) {
|
|
125
|
+
return null
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
// Chips are unique by value
|
|
129
|
+
if (this._chips.includes(trimmedValue)) {
|
|
130
|
+
return null
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
// Check max chips limit
|
|
134
|
+
if (this._config.maxChips !== null && this._chips.length >= this._config.maxChips) {
|
|
135
|
+
return null
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
const addEvent = EventHandler.trigger(this._element, EVENT_ADD, {
|
|
139
|
+
value: trimmedValue,
|
|
140
|
+
relatedTarget: this._input
|
|
141
|
+
})
|
|
142
|
+
|
|
143
|
+
if (addEvent.defaultPrevented) {
|
|
144
|
+
return null
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
const chip = this._createChip(trimmedValue)
|
|
148
|
+
this._element.insertBefore(chip, this._input)
|
|
149
|
+
this._chips.push(trimmedValue)
|
|
150
|
+
|
|
151
|
+
const values = this.getValues()
|
|
152
|
+
this._hiddenInput.value = values.join(',')
|
|
153
|
+
|
|
154
|
+
EventHandler.trigger(this._element, EVENT_CHANGE, {
|
|
155
|
+
values
|
|
156
|
+
})
|
|
157
|
+
|
|
158
|
+
return chip
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
remove(chipOrValue) {
|
|
162
|
+
if (this._disabled || this._readonly) {
|
|
163
|
+
return false
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
let chip
|
|
167
|
+
let value
|
|
168
|
+
|
|
169
|
+
if (typeof chipOrValue === 'string') {
|
|
170
|
+
value = chipOrValue
|
|
171
|
+
chip = this._findChipByValue(value)
|
|
172
|
+
} else {
|
|
173
|
+
chip = chipOrValue
|
|
174
|
+
value = this._getChipValue(chip)
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
if (!chip || !value) {
|
|
178
|
+
return false
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
const removeEvent = EventHandler.trigger(this._element, EVENT_REMOVE, {
|
|
182
|
+
value,
|
|
183
|
+
chip,
|
|
184
|
+
relatedTarget: this._input
|
|
185
|
+
})
|
|
186
|
+
|
|
187
|
+
if (removeEvent.defaultPrevented) {
|
|
188
|
+
return false
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
const chipInstance = Chip.getInstance(chip)
|
|
192
|
+
if (chipInstance) {
|
|
193
|
+
chipInstance.remove()
|
|
194
|
+
} else {
|
|
195
|
+
chip.remove()
|
|
196
|
+
this._handleChipRemoved(chip, value)
|
|
197
|
+
}
|
|
198
|
+
|
|
199
|
+
return !chip.isConnected
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
removeSelected() {
|
|
203
|
+
const chipsToRemove = this._getSelectedChipElements()
|
|
204
|
+
for (const chip of chipsToRemove) {
|
|
205
|
+
this.remove(chip)
|
|
206
|
+
}
|
|
207
|
+
|
|
208
|
+
this._input?.focus()
|
|
209
|
+
}
|
|
210
|
+
|
|
211
|
+
getValues() {
|
|
212
|
+
return [...this._chips]
|
|
213
|
+
}
|
|
214
|
+
|
|
215
|
+
getSelectedValues() {
|
|
216
|
+
return this._getSelectedChipElements().map(chip => this._getChipValue(chip))
|
|
217
|
+
}
|
|
218
|
+
|
|
219
|
+
clear() {
|
|
220
|
+
const chips = SelectorEngine.find(SELECTOR_CHIP, this._element)
|
|
221
|
+
for (const chip of chips) {
|
|
222
|
+
this.remove(chip)
|
|
223
|
+
}
|
|
224
|
+
}
|
|
225
|
+
|
|
226
|
+
clearSelection() {
|
|
227
|
+
for (const chip of this._getSelectedChipElements()) {
|
|
228
|
+
Chip.getInstance(chip)?.deselect()
|
|
229
|
+
}
|
|
230
|
+
|
|
231
|
+
EventHandler.trigger(this._element, EVENT_SELECT, {
|
|
232
|
+
selected: []
|
|
233
|
+
})
|
|
234
|
+
}
|
|
235
|
+
|
|
236
|
+
selectChip(chip) {
|
|
237
|
+
const chipElements = this._getChipElements()
|
|
238
|
+
|
|
239
|
+
if (!chipElements.includes(chip)) {
|
|
240
|
+
return
|
|
241
|
+
}
|
|
242
|
+
|
|
243
|
+
const chipInstance = Chip.getInstance(chip)
|
|
244
|
+
if (!chipInstance) {
|
|
245
|
+
return
|
|
246
|
+
}
|
|
247
|
+
|
|
248
|
+
chipInstance.select()
|
|
249
|
+
}
|
|
250
|
+
|
|
251
|
+
focus() {
|
|
252
|
+
this._input?.focus()
|
|
253
|
+
}
|
|
254
|
+
|
|
255
|
+
// Private
|
|
256
|
+
_emitSelectionChange() {
|
|
257
|
+
EventHandler.trigger(this._element, EVENT_SELECT, {
|
|
258
|
+
selected: this.getSelectedValues()
|
|
259
|
+
})
|
|
260
|
+
}
|
|
261
|
+
|
|
262
|
+
_getChipElements() {
|
|
263
|
+
return SelectorEngine.find(SELECTOR_CHIP, this._element)
|
|
264
|
+
}
|
|
265
|
+
|
|
266
|
+
_getSelectedChipElements() {
|
|
267
|
+
return SelectorEngine.find(SELECTOR_CHIP_ACTIVE, this._element)
|
|
268
|
+
}
|
|
269
|
+
|
|
270
|
+
_createInput() {
|
|
271
|
+
const input = document.createElement('input')
|
|
272
|
+
const label = SelectorEngine.findOne(SELECTOR_CHIP_INPUT_LABEL, this._element)
|
|
273
|
+
const labelFor = label?.getAttribute('for')
|
|
274
|
+
const generatedInputId = labelFor || getUID(`${this.constructor.NAME}-input`)
|
|
275
|
+
|
|
276
|
+
input.type = 'text'
|
|
277
|
+
input.className = CLASS_NAME_CHIP_INPUT_FIELD
|
|
278
|
+
input.id = generatedInputId
|
|
279
|
+
if (this._config.placeholder) {
|
|
280
|
+
input.placeholder = this._config.placeholder
|
|
281
|
+
}
|
|
282
|
+
|
|
283
|
+
if (label && !labelFor) {
|
|
284
|
+
label.setAttribute('for', generatedInputId)
|
|
285
|
+
}
|
|
286
|
+
|
|
287
|
+
this._input = input
|
|
288
|
+
this._setInputSize()
|
|
289
|
+
this._element.append(input)
|
|
290
|
+
}
|
|
291
|
+
|
|
292
|
+
_createHiddenInput() {
|
|
293
|
+
const hiddenInput = document.createElement('input')
|
|
294
|
+
hiddenInput.type = 'hidden'
|
|
295
|
+
hiddenInput.id = this._uniqueId
|
|
296
|
+
hiddenInput.name = this._config.name || this._uniqueId
|
|
297
|
+
|
|
298
|
+
this._element.append(hiddenInput)
|
|
299
|
+
this._hiddenInput = hiddenInput
|
|
300
|
+
this._hiddenInput.value = this.getValues().join(',')
|
|
301
|
+
}
|
|
302
|
+
|
|
303
|
+
_createChip(value) {
|
|
304
|
+
const chip = document.createElement('span')
|
|
305
|
+
chip.className = CLASS_NAME_CHIP
|
|
306
|
+
chip.dataset.coreuiChipValue = value
|
|
307
|
+
chip.append(document.createTextNode(value))
|
|
308
|
+
this._applyChipClassName(chip, value)
|
|
309
|
+
|
|
310
|
+
this._setupChip(chip)
|
|
311
|
+
|
|
312
|
+
return chip
|
|
313
|
+
}
|
|
314
|
+
|
|
315
|
+
_createChipFromInput() {
|
|
316
|
+
if (this._disabled || this._readonly) {
|
|
317
|
+
return
|
|
318
|
+
}
|
|
319
|
+
|
|
320
|
+
const value = this._input.value.trim()
|
|
321
|
+
if (value) {
|
|
322
|
+
this.add(value)
|
|
323
|
+
this._input.value = ''
|
|
324
|
+
this._setInputSize()
|
|
325
|
+
}
|
|
326
|
+
}
|
|
327
|
+
|
|
328
|
+
_findChipByValue(value) {
|
|
329
|
+
const chips = this._getChipElements()
|
|
330
|
+
return chips.find(chip => this._getChipValue(chip) === value)
|
|
331
|
+
}
|
|
332
|
+
|
|
333
|
+
_getChipValue(chip) {
|
|
334
|
+
if (chip.dataset.coreuiChipValue) {
|
|
335
|
+
return chip.dataset.coreuiChipValue
|
|
336
|
+
}
|
|
337
|
+
|
|
338
|
+
const clone = chip.cloneNode(true)
|
|
339
|
+
const remove = SelectorEngine.findOne(SELECTOR_CHIP_REMOVE, clone)
|
|
340
|
+
if (remove) {
|
|
341
|
+
remove.remove()
|
|
342
|
+
}
|
|
343
|
+
|
|
344
|
+
return clone.textContent?.trim() || ''
|
|
345
|
+
}
|
|
346
|
+
|
|
347
|
+
_initializeExistingChips() {
|
|
348
|
+
const existingChips = SelectorEngine.find(SELECTOR_CHIP, this._element)
|
|
349
|
+
for (const chip of existingChips) {
|
|
350
|
+
const value = this._getChipValue(chip)
|
|
351
|
+
if (value) {
|
|
352
|
+
this._chips.push(value)
|
|
353
|
+
this._applyChipClassName(chip, value)
|
|
354
|
+
this._setupChip(chip)
|
|
355
|
+
}
|
|
356
|
+
}
|
|
357
|
+
}
|
|
358
|
+
|
|
359
|
+
_applyChipClassName(chip, value) {
|
|
360
|
+
const className = this._resolveChipClassName(value)
|
|
361
|
+
if (!className) {
|
|
362
|
+
return
|
|
363
|
+
}
|
|
364
|
+
|
|
365
|
+
chip.classList.add(...className.split(/\s+/).filter(Boolean))
|
|
366
|
+
}
|
|
367
|
+
|
|
368
|
+
_resolveChipClassName(value) {
|
|
369
|
+
const { chipClassName } = this._config
|
|
370
|
+
if (!chipClassName) {
|
|
371
|
+
return ''
|
|
372
|
+
}
|
|
373
|
+
|
|
374
|
+
if (typeof chipClassName === 'function') {
|
|
375
|
+
const resolvedClassName = chipClassName(value)
|
|
376
|
+
return typeof resolvedClassName === 'string' ? resolvedClassName : ''
|
|
377
|
+
}
|
|
378
|
+
|
|
379
|
+
return typeof chipClassName === 'string' ? chipClassName : ''
|
|
380
|
+
}
|
|
381
|
+
|
|
382
|
+
_setupChip(chip) {
|
|
383
|
+
Chip.getOrCreateInstance(chip, {
|
|
384
|
+
ariaRemoveLabel: `Remove ${this._getChipValue(chip)}`,
|
|
385
|
+
disabled: this._disabled,
|
|
386
|
+
removable: this._config.removable && !this._readonly && !this._disabled,
|
|
387
|
+
removeIcon: this._config.removeIcon,
|
|
388
|
+
selectable: this._config.selectable
|
|
389
|
+
})
|
|
390
|
+
|
|
391
|
+
const removeButton = SelectorEngine.findOne(SELECTOR_CHIP_REMOVE, chip)
|
|
392
|
+
if (removeButton) {
|
|
393
|
+
removeButton.disabled = this._disabled || this._readonly
|
|
394
|
+
}
|
|
395
|
+
}
|
|
396
|
+
|
|
397
|
+
_applyInteractionState() {
|
|
398
|
+
this._element.classList.toggle(CLASS_NAME_DISABLED, this._disabled)
|
|
399
|
+
this._input.disabled = this._disabled
|
|
400
|
+
this._input.readOnly = !this._disabled && this._readonly
|
|
401
|
+
this._element.setAttribute('aria-disabled', this._disabled ? 'true' : 'false')
|
|
402
|
+
this._element.setAttribute('aria-readonly', this._readonly ? 'true' : 'false')
|
|
403
|
+
}
|
|
404
|
+
|
|
405
|
+
_addEventListeners() {
|
|
406
|
+
EventHandler.on(this._element, 'keydown', event => {
|
|
407
|
+
if (event.target === this._input) {
|
|
408
|
+
return
|
|
409
|
+
}
|
|
410
|
+
|
|
411
|
+
if (event.key.length === 1) {
|
|
412
|
+
this._input.focus()
|
|
413
|
+
}
|
|
414
|
+
})
|
|
415
|
+
EventHandler.on(this._input, 'keydown', event => this._handleInputKeydown(event))
|
|
416
|
+
EventHandler.on(this._input, 'input', event => this._handleInput(event))
|
|
417
|
+
EventHandler.on(this._input, 'paste', event => this._handlePaste(event))
|
|
418
|
+
EventHandler.on(this._input, 'focus', () => this.clearSelection())
|
|
419
|
+
|
|
420
|
+
if (this._config.createOnBlur) {
|
|
421
|
+
EventHandler.on(this._input, 'blur', event => {
|
|
422
|
+
// Don't create chip if clicking on a chip
|
|
423
|
+
if (!event.relatedTarget?.closest(SELECTOR_CHIP)) {
|
|
424
|
+
this._createChipFromInput()
|
|
425
|
+
}
|
|
426
|
+
})
|
|
427
|
+
}
|
|
428
|
+
|
|
429
|
+
EventHandler.on(this._element, 'selected.coreui.chip', SELECTOR_CHIP, () => {
|
|
430
|
+
this._emitSelectionChange()
|
|
431
|
+
})
|
|
432
|
+
|
|
433
|
+
EventHandler.on(this._element, 'deselected.coreui.chip', SELECTOR_CHIP, () => {
|
|
434
|
+
this._emitSelectionChange()
|
|
435
|
+
})
|
|
436
|
+
|
|
437
|
+
EventHandler.on(this._element, 'remove.coreui.chip', SELECTOR_CHIP, event => {
|
|
438
|
+
if (this._disabled || this._readonly) {
|
|
439
|
+
event.preventDefault()
|
|
440
|
+
}
|
|
441
|
+
})
|
|
442
|
+
|
|
443
|
+
EventHandler.on(this._element, 'removed.coreui.chip', SELECTOR_CHIP, event => {
|
|
444
|
+
const chip = event.target.closest(SELECTOR_CHIP)
|
|
445
|
+
if (chip) {
|
|
446
|
+
this._handleChipRemoved(chip)
|
|
447
|
+
const focusableChips = SelectorEngine.find(SELECTOR_FOCUSABLE_ITEMS, this._element)
|
|
448
|
+
|
|
449
|
+
if (focusableChips.length > 0) {
|
|
450
|
+
this._input?.focus()
|
|
451
|
+
}
|
|
452
|
+
|
|
453
|
+
this._emitSelectionChange()
|
|
454
|
+
}
|
|
455
|
+
})
|
|
456
|
+
|
|
457
|
+
// Focus input when clicking container background
|
|
458
|
+
EventHandler.on(this._element, 'click', event => {
|
|
459
|
+
if (event.target === this._element) {
|
|
460
|
+
this._input?.focus()
|
|
461
|
+
}
|
|
462
|
+
})
|
|
463
|
+
}
|
|
464
|
+
|
|
465
|
+
_handleInputKeydown(event) {
|
|
466
|
+
const { key } = event
|
|
467
|
+
|
|
468
|
+
switch (key) {
|
|
469
|
+
case 'Enter': {
|
|
470
|
+
event.preventDefault()
|
|
471
|
+
this._createChipFromInput()
|
|
472
|
+
break
|
|
473
|
+
}
|
|
474
|
+
|
|
475
|
+
case 'Backspace':
|
|
476
|
+
case 'Delete': {
|
|
477
|
+
if (this._input.value === '') {
|
|
478
|
+
event.preventDefault()
|
|
479
|
+
const chips = this._getChipElements()
|
|
480
|
+
|
|
481
|
+
if (chips.length > 0) {
|
|
482
|
+
const lastChip = chips.at(-1)
|
|
483
|
+
lastChip.focus()
|
|
484
|
+
}
|
|
485
|
+
}
|
|
486
|
+
|
|
487
|
+
break
|
|
488
|
+
}
|
|
489
|
+
|
|
490
|
+
case 'ArrowLeft': {
|
|
491
|
+
if (this._input.selectionStart === 0 && this._input.selectionEnd === 0) {
|
|
492
|
+
event.preventDefault()
|
|
493
|
+
const chips = this._getChipElements()
|
|
494
|
+
|
|
495
|
+
if (chips.length > 0) {
|
|
496
|
+
const lastChip = chips.at(-1)
|
|
497
|
+
lastChip.focus()
|
|
498
|
+
}
|
|
499
|
+
}
|
|
500
|
+
|
|
501
|
+
break
|
|
502
|
+
}
|
|
503
|
+
|
|
504
|
+
case 'Escape': {
|
|
505
|
+
this._input.value = ''
|
|
506
|
+
this._input.blur()
|
|
507
|
+
break
|
|
508
|
+
}
|
|
509
|
+
|
|
510
|
+
// No default
|
|
511
|
+
}
|
|
512
|
+
}
|
|
513
|
+
|
|
514
|
+
_handleChipRemoved(chip, value = null) {
|
|
515
|
+
const chipValue = value || this._getChipValue(chip)
|
|
516
|
+
const valueIndex = this._chips.indexOf(chipValue)
|
|
517
|
+
if (valueIndex !== -1) {
|
|
518
|
+
this._chips.splice(valueIndex, 1)
|
|
519
|
+
}
|
|
520
|
+
|
|
521
|
+
const values = this.getValues()
|
|
522
|
+
this._hiddenInput.value = values.join(',')
|
|
523
|
+
|
|
524
|
+
EventHandler.trigger(this._element, EVENT_CHANGE, {
|
|
525
|
+
values
|
|
526
|
+
})
|
|
527
|
+
}
|
|
528
|
+
|
|
529
|
+
_handleInput(event) {
|
|
530
|
+
if (this._disabled || this._readonly) {
|
|
531
|
+
return
|
|
532
|
+
}
|
|
533
|
+
|
|
534
|
+
const { value } = event.target
|
|
535
|
+
const { separator } = this._config
|
|
536
|
+
|
|
537
|
+
if (separator && value.includes(separator)) {
|
|
538
|
+
const parts = value.split(separator)
|
|
539
|
+
for (const part of parts.slice(0, -1)) {
|
|
540
|
+
this.add(part.trim())
|
|
541
|
+
}
|
|
542
|
+
|
|
543
|
+
this._input.value = parts.at(-1)
|
|
544
|
+
}
|
|
545
|
+
|
|
546
|
+
this._setInputSize()
|
|
547
|
+
EventHandler.trigger(this._element, EVENT_INPUT, {
|
|
548
|
+
value: this._input.value,
|
|
549
|
+
relatedTarget: this._input
|
|
550
|
+
})
|
|
551
|
+
}
|
|
552
|
+
|
|
553
|
+
_handlePaste(event) {
|
|
554
|
+
if (this._disabled || this._readonly) {
|
|
555
|
+
return
|
|
556
|
+
}
|
|
557
|
+
|
|
558
|
+
const { separator } = this._config
|
|
559
|
+
if (!separator) {
|
|
560
|
+
return
|
|
561
|
+
}
|
|
562
|
+
|
|
563
|
+
const pastedData = (event.clipboardData || window.clipboardData).getData('text')
|
|
564
|
+
if (pastedData.includes(separator)) {
|
|
565
|
+
event.preventDefault()
|
|
566
|
+
|
|
567
|
+
const parts = pastedData.split(separator)
|
|
568
|
+
for (const part of parts) {
|
|
569
|
+
this.add(part.trim())
|
|
570
|
+
}
|
|
571
|
+
}
|
|
572
|
+
}
|
|
573
|
+
|
|
574
|
+
_setInputSize() {
|
|
575
|
+
if (!this._input) {
|
|
576
|
+
return
|
|
577
|
+
}
|
|
578
|
+
|
|
579
|
+
this._input.size = Math.max(this._input.placeholder.length, this._input.value.length) || 1
|
|
580
|
+
}
|
|
581
|
+
}
|
|
582
|
+
|
|
583
|
+
/**
|
|
584
|
+
* Data API implementation
|
|
585
|
+
*/
|
|
586
|
+
|
|
587
|
+
EventHandler.on(document, `DOMContentLoaded${EVENT_KEY}${DATA_API_KEY}`, () => {
|
|
588
|
+
for (const element of SelectorEngine.find(SELECTOR_DATA_CHIP_INPUT)) {
|
|
589
|
+
ChipInput.getOrCreateInstance(element)
|
|
590
|
+
}
|
|
591
|
+
})
|
|
592
|
+
|
|
593
|
+
export default ChipInput
|