@coreui/coreui 5.5.0 → 5.6.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.
Files changed (116) hide show
  1. package/LICENSE +1 -1
  2. package/README.md +5 -3
  3. package/dist/css/coreui-grid.css +2 -2
  4. package/dist/css/coreui-grid.css.map +1 -1
  5. package/dist/css/coreui-grid.min.css +2 -2
  6. package/dist/css/coreui-grid.min.css.map +1 -1
  7. package/dist/css/coreui-grid.rtl.css +2 -2
  8. package/dist/css/coreui-grid.rtl.css.map +1 -1
  9. package/dist/css/coreui-grid.rtl.min.css +2 -2
  10. package/dist/css/coreui-grid.rtl.min.css.map +1 -1
  11. package/dist/css/coreui-reboot.css +11 -2
  12. package/dist/css/coreui-reboot.css.map +1 -1
  13. package/dist/css/coreui-reboot.min.css +3 -3
  14. package/dist/css/coreui-reboot.min.css.map +1 -1
  15. package/dist/css/coreui-reboot.rtl.css +11 -2
  16. package/dist/css/coreui-reboot.rtl.css.map +1 -1
  17. package/dist/css/coreui-reboot.rtl.min.css +3 -3
  18. package/dist/css/coreui-reboot.rtl.min.css.map +1 -1
  19. package/dist/css/coreui-utilities.css +11 -2
  20. package/dist/css/coreui-utilities.css.map +1 -1
  21. package/dist/css/coreui-utilities.min.css +3 -3
  22. package/dist/css/coreui-utilities.min.css.map +1 -1
  23. package/dist/css/coreui-utilities.rtl.css +11 -2
  24. package/dist/css/coreui-utilities.rtl.css.map +1 -1
  25. package/dist/css/coreui-utilities.rtl.min.css +3 -3
  26. package/dist/css/coreui-utilities.rtl.min.css.map +1 -1
  27. package/dist/css/coreui.css +337 -2
  28. package/dist/css/coreui.css.map +1 -1
  29. package/dist/css/coreui.min.css +3 -3
  30. package/dist/css/coreui.min.css.map +1 -1
  31. package/dist/css/coreui.rtl.css +332 -2
  32. package/dist/css/coreui.rtl.css.map +1 -1
  33. package/dist/css/coreui.rtl.min.css +3 -3
  34. package/dist/css/coreui.rtl.min.css.map +1 -1
  35. package/dist/css/themes/bootstrap/bootstrap.css +337 -2
  36. package/dist/css/themes/bootstrap/bootstrap.css.map +1 -1
  37. package/dist/css/themes/bootstrap/bootstrap.min.css +3 -3
  38. package/dist/css/themes/bootstrap/bootstrap.min.css.map +1 -1
  39. package/dist/css/themes/bootstrap/bootstrap.rtl.css +332 -2
  40. package/dist/css/themes/bootstrap/bootstrap.rtl.css.map +1 -1
  41. package/dist/css/themes/bootstrap/bootstrap.rtl.min.css +3 -3
  42. package/dist/css/themes/bootstrap/bootstrap.rtl.min.css.map +1 -1
  43. package/dist/js/bootstrap.bundle.js +874 -60
  44. package/dist/js/bootstrap.bundle.js.map +1 -1
  45. package/dist/js/bootstrap.bundle.min.js +3 -3
  46. package/dist/js/bootstrap.bundle.min.js.map +1 -1
  47. package/dist/js/bootstrap.esm.js +873 -53
  48. package/dist/js/bootstrap.esm.js.map +1 -1
  49. package/dist/js/bootstrap.esm.min.js +3 -3
  50. package/dist/js/bootstrap.esm.min.js.map +1 -1
  51. package/dist/js/bootstrap.js +874 -52
  52. package/dist/js/bootstrap.js.map +1 -1
  53. package/dist/js/bootstrap.min.js +3 -3
  54. package/dist/js/bootstrap.min.js.map +1 -1
  55. package/dist/js/coreui.bundle.js +874 -60
  56. package/dist/js/coreui.bundle.js.map +1 -1
  57. package/dist/js/coreui.bundle.min.js +3 -3
  58. package/dist/js/coreui.bundle.min.js.map +1 -1
  59. package/dist/js/coreui.esm.js +873 -53
  60. package/dist/js/coreui.esm.js.map +1 -1
  61. package/dist/js/coreui.esm.min.js +3 -3
  62. package/dist/js/coreui.esm.min.js.map +1 -1
  63. package/dist/js/coreui.js +874 -52
  64. package/dist/js/coreui.js.map +1 -1
  65. package/dist/js/coreui.min.js +3 -3
  66. package/dist/js/coreui.min.js.map +1 -1
  67. package/js/dist/alert.js +2 -2
  68. package/js/dist/base-component.js +3 -3
  69. package/js/dist/base-component.js.map +1 -1
  70. package/js/dist/button.js +2 -2
  71. package/js/dist/carousel.js +2 -2
  72. package/js/dist/chip-input.js +528 -0
  73. package/js/dist/chip-input.js.map +1 -0
  74. package/js/dist/chip.js +322 -0
  75. package/js/dist/chip.js.map +1 -0
  76. package/js/dist/collapse.js +2 -2
  77. package/js/dist/dom/data.js +2 -2
  78. package/js/dist/dom/event-handler.js +2 -2
  79. package/js/dist/dom/manipulator.js +2 -2
  80. package/js/dist/dom/selector-engine.js +2 -2
  81. package/js/dist/dropdown.js +2 -2
  82. package/js/dist/modal.js +2 -2
  83. package/js/dist/navigation.js +2 -2
  84. package/js/dist/offcanvas.js +2 -2
  85. package/js/dist/popover.js +2 -2
  86. package/js/dist/scrollspy.js +2 -2
  87. package/js/dist/sidebar.js +2 -2
  88. package/js/dist/tab.js +2 -2
  89. package/js/dist/toast.js +2 -2
  90. package/js/dist/tooltip.js +2 -2
  91. package/js/dist/util/backdrop.js +2 -2
  92. package/js/dist/util/component-functions.js +2 -2
  93. package/js/dist/util/config.js +2 -2
  94. package/js/dist/util/focustrap.js +2 -2
  95. package/js/dist/util/index.js +2 -2
  96. package/js/dist/util/sanitizer.js +2 -2
  97. package/js/dist/util/scrollbar.js +2 -2
  98. package/js/dist/util/swipe.js +2 -2
  99. package/js/dist/util/template-factory.js +2 -2
  100. package/js/index.esm.js +2 -0
  101. package/js/index.umd.js +4 -0
  102. package/js/src/base-component.js +1 -1
  103. package/js/src/chip-input.js +595 -0
  104. package/js/src/chip.js +365 -0
  105. package/package.json +20 -20
  106. package/scss/_banner.scss +2 -2
  107. package/scss/_chip.import.scss +1 -0
  108. package/scss/_chip.scss +261 -0
  109. package/scss/_forms.scss +1 -0
  110. package/scss/_maps.scss +14 -0
  111. package/scss/_root.scss +5 -0
  112. package/scss/coreui.scss +1 -0
  113. package/scss/forms/_chip-input.import.scss +1 -0
  114. package/scss/forms/_chip-input.scss +109 -0
  115. package/scss/mixins/_chip.scss +14 -0
  116. package/scss/mixins/_focus-ring.scss +9 -0
@@ -1,6 +1,6 @@
1
1
  /*!
2
- * CoreUI focustrap.js v5.5.0 (https://coreui.io)
3
- * Copyright 2025 The CoreUI Team (https://github.com/orgs/coreui/people)
2
+ * CoreUI focustrap.js v5.6.0 (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 index.js v5.5.0 (https://coreui.io)
3
- * Copyright 2025 The CoreUI Team (https://github.com/orgs/coreui/people)
2
+ * CoreUI index.js v5.6.0 (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.5.0 (https://coreui.io)
3
- * Copyright 2025 The CoreUI Team (https://github.com/orgs/coreui/people)
2
+ * CoreUI sanitizer.js v5.6.0 (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.5.0 (https://coreui.io)
3
- * Copyright 2025 The CoreUI Team (https://github.com/orgs/coreui/people)
2
+ * CoreUI scrollbar.js v5.6.0 (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 swipe.js v5.5.0 (https://coreui.io)
3
- * Copyright 2025 The CoreUI Team (https://github.com/orgs/coreui/people)
2
+ * CoreUI swipe.js v5.6.0 (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.5.0 (https://coreui.io)
3
- * Copyright 2025 The CoreUI Team (https://github.com/orgs/coreui/people)
2
+ * CoreUI template-factory.js v5.6.0 (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,
@@ -17,7 +17,7 @@ import { executeAfterTransition, getElement } from './util/index.js'
17
17
  * Constants
18
18
  */
19
19
 
20
- const VERSION = '5.5.0'
20
+ const VERSION = '5.6.0'
21
21
 
22
22
  /**
23
23
  * Class definition
@@ -0,0 +1,595 @@
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
+ // eslint-disable-next-line no-console
413
+ console.log(event.key.length)
414
+ this._input.focus()
415
+ }
416
+ })
417
+ EventHandler.on(this._input, 'keydown', event => this._handleInputKeydown(event))
418
+ EventHandler.on(this._input, 'input', event => this._handleInput(event))
419
+ EventHandler.on(this._input, 'paste', event => this._handlePaste(event))
420
+ EventHandler.on(this._input, 'focus', () => this.clearSelection())
421
+
422
+ if (this._config.createOnBlur) {
423
+ EventHandler.on(this._input, 'blur', event => {
424
+ // Don't create chip if clicking on a chip
425
+ if (!event.relatedTarget?.closest(SELECTOR_CHIP)) {
426
+ this._createChipFromInput()
427
+ }
428
+ })
429
+ }
430
+
431
+ EventHandler.on(this._element, 'selected.coreui.chip', SELECTOR_CHIP, () => {
432
+ this._emitSelectionChange()
433
+ })
434
+
435
+ EventHandler.on(this._element, 'deselected.coreui.chip', SELECTOR_CHIP, () => {
436
+ this._emitSelectionChange()
437
+ })
438
+
439
+ EventHandler.on(this._element, 'remove.coreui.chip', SELECTOR_CHIP, event => {
440
+ if (this._disabled || this._readonly) {
441
+ event.preventDefault()
442
+ }
443
+ })
444
+
445
+ EventHandler.on(this._element, 'removed.coreui.chip', SELECTOR_CHIP, event => {
446
+ const chip = event.target.closest(SELECTOR_CHIP)
447
+ if (chip) {
448
+ this._handleChipRemoved(chip)
449
+ const focusableChips = SelectorEngine.find(SELECTOR_FOCUSABLE_ITEMS, this._element)
450
+
451
+ if (focusableChips.length > 0) {
452
+ this._input?.focus()
453
+ }
454
+
455
+ this._emitSelectionChange()
456
+ }
457
+ })
458
+
459
+ // Focus input when clicking container background
460
+ EventHandler.on(this._element, 'click', event => {
461
+ if (event.target === this._element) {
462
+ this._input?.focus()
463
+ }
464
+ })
465
+ }
466
+
467
+ _handleInputKeydown(event) {
468
+ const { key } = event
469
+
470
+ switch (key) {
471
+ case 'Enter': {
472
+ event.preventDefault()
473
+ this._createChipFromInput()
474
+ break
475
+ }
476
+
477
+ case 'Backspace':
478
+ case 'Delete': {
479
+ if (this._input.value === '') {
480
+ event.preventDefault()
481
+ const chips = this._getChipElements()
482
+
483
+ if (chips.length > 0) {
484
+ const lastChip = chips.at(-1)
485
+ lastChip.focus()
486
+ }
487
+ }
488
+
489
+ break
490
+ }
491
+
492
+ case 'ArrowLeft': {
493
+ if (this._input.selectionStart === 0 && this._input.selectionEnd === 0) {
494
+ event.preventDefault()
495
+ const chips = this._getChipElements()
496
+
497
+ if (chips.length > 0) {
498
+ const lastChip = chips.at(-1)
499
+ lastChip.focus()
500
+ }
501
+ }
502
+
503
+ break
504
+ }
505
+
506
+ case 'Escape': {
507
+ this._input.value = ''
508
+ this._input.blur()
509
+ break
510
+ }
511
+
512
+ // No default
513
+ }
514
+ }
515
+
516
+ _handleChipRemoved(chip, value = null) {
517
+ const chipValue = value || this._getChipValue(chip)
518
+ const valueIndex = this._chips.indexOf(chipValue)
519
+ if (valueIndex !== -1) {
520
+ this._chips.splice(valueIndex, 1)
521
+ }
522
+
523
+ const values = this.getValues()
524
+ this._hiddenInput.value = values.join(',')
525
+
526
+ EventHandler.trigger(this._element, EVENT_CHANGE, {
527
+ values
528
+ })
529
+ }
530
+
531
+ _handleInput(event) {
532
+ if (this._disabled || this._readonly) {
533
+ return
534
+ }
535
+
536
+ const { value } = event.target
537
+ const { separator } = this._config
538
+
539
+ if (separator && value.includes(separator)) {
540
+ const parts = value.split(separator)
541
+ for (const part of parts.slice(0, -1)) {
542
+ this.add(part.trim())
543
+ }
544
+
545
+ this._input.value = parts.at(-1)
546
+ }
547
+
548
+ this._setInputSize()
549
+ EventHandler.trigger(this._element, EVENT_INPUT, {
550
+ value: this._input.value,
551
+ relatedTarget: this._input
552
+ })
553
+ }
554
+
555
+ _handlePaste(event) {
556
+ if (this._disabled || this._readonly) {
557
+ return
558
+ }
559
+
560
+ const { separator } = this._config
561
+ if (!separator) {
562
+ return
563
+ }
564
+
565
+ const pastedData = (event.clipboardData || window.clipboardData).getData('text')
566
+ if (pastedData.includes(separator)) {
567
+ event.preventDefault()
568
+
569
+ const parts = pastedData.split(separator)
570
+ for (const part of parts) {
571
+ this.add(part.trim())
572
+ }
573
+ }
574
+ }
575
+
576
+ _setInputSize() {
577
+ if (!this._input) {
578
+ return
579
+ }
580
+
581
+ this._input.size = Math.max(this._input.placeholder.length, this._input.value.length) || 1
582
+ }
583
+ }
584
+
585
+ /**
586
+ * Data API implementation
587
+ */
588
+
589
+ EventHandler.on(document, `DOMContentLoaded${EVENT_KEY}${DATA_API_KEY}`, () => {
590
+ for (const element of SelectorEngine.find(SELECTOR_DATA_CHIP_INPUT)) {
591
+ ChipInput.getOrCreateInstance(element)
592
+ }
593
+ })
594
+
595
+ export default ChipInput