@vonage/vivid 4.24.0 → 4.25.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 (392) hide show
  1. package/custom-elements.json +12314 -4711
  2. package/elevation/index.cjs +1 -1
  3. package/elevation/index.js +1 -1
  4. package/index.cjs +112 -150
  5. package/index.js +37 -35
  6. package/lib/accordion-item/accordion-item.d.ts +6 -0
  7. package/lib/action-group/action-group.d.ts +6 -0
  8. package/lib/alert/alert.d.ts +20 -0
  9. package/lib/audio-player/audio-player.d.ts +6 -0
  10. package/lib/badge/badge.d.ts +9 -1
  11. package/lib/banner/banner.d.ts +25 -0
  12. package/lib/breadcrumb/breadcrumb.d.ts +6 -0
  13. package/lib/breadcrumb-item/breadcrumb-item.d.ts +63 -7
  14. package/lib/button/button.d.ts +732 -7
  15. package/lib/button/locale.d.ts +3 -0
  16. package/lib/calendar-event/calendar-event.d.ts +6 -0
  17. package/lib/card/card.d.ts +394 -2
  18. package/lib/card/card.template.d.ts +2 -1
  19. package/lib/checkbox/checkbox.d.ts +1822 -5
  20. package/lib/combobox/combobox.d.ts +1827 -20
  21. package/lib/data-grid/data-grid-cell.d.ts +339 -1
  22. package/lib/data-grid/locale.d.ts +5 -0
  23. package/lib/date-picker/date-picker.d.ts +1676 -207
  24. package/lib/date-range-picker/date-range-picker.d.ts +840 -107
  25. package/lib/date-time-picker/date-time-picker.d.ts +1678 -209
  26. package/lib/dial-pad/dial-pad.d.ts +8 -0
  27. package/lib/dialog/dialog.d.ts +12 -0
  28. package/lib/divider/divider.d.ts +6 -0
  29. package/lib/fab/fab.d.ts +6 -0
  30. package/lib/file-picker/file-picker.d.ts +1508 -30
  31. package/lib/header/header.d.ts +6 -0
  32. package/lib/icon/icon.d.ts +1 -0
  33. package/lib/icon/icon.template.d.ts +2 -1
  34. package/lib/menu/menu.d.ts +16 -7
  35. package/lib/menu/name.d.ts +1 -0
  36. package/lib/menu-item/menu-item.d.ts +14 -2
  37. package/lib/nav/nav.d.ts +6 -0
  38. package/lib/nav-disclosure/nav-disclosure.d.ts +13 -0
  39. package/lib/nav-item/nav-item.d.ts +405 -3
  40. package/lib/note/note.d.ts +6 -0
  41. package/lib/number-field/number-field.d.ts +1857 -36
  42. package/lib/option/option.d.ts +12 -0
  43. package/lib/progress/progress.d.ts +6 -0
  44. package/lib/progress-ring/progress-ring.d.ts +6 -0
  45. package/lib/radio/radio.d.ts +1137 -4
  46. package/lib/radio-group/radio-group.d.ts +20 -2
  47. package/lib/range-slider/range-slider.d.ts +752 -5
  48. package/lib/rich-text-editor/definition.d.ts +2 -2
  49. package/lib/rich-text-editor/facades/vivid-prose-mirror.facade.d.ts +3 -1
  50. package/lib/rich-text-editor/locale.d.ts +1 -0
  51. package/lib/rich-text-editor/menubar/menubar.d.ts +6 -0
  52. package/lib/rich-text-editor/rich-text-editor.d.ts +352 -2
  53. package/lib/searchable-select/option-tag.d.ts +6 -0
  54. package/lib/searchable-select/searchable-select.d.ts +1857 -36
  55. package/lib/select/select.d.ts +1843 -28
  56. package/lib/selectable-box/selectable-box.d.ts +6 -0
  57. package/lib/slider/slider.d.ts +384 -2
  58. package/lib/split-button/split-button.d.ts +18 -0
  59. package/lib/switch/switch.d.ts +386 -3
  60. package/lib/tab/tab.d.ts +18 -1
  61. package/lib/tab-panel/tab-panel.d.ts +6 -0
  62. package/lib/tag/tag.d.ts +12 -0
  63. package/lib/tag-group/tag-group.d.ts +6 -0
  64. package/lib/text-area/text-area.d.ts +2174 -19
  65. package/lib/text-field/text-field.d.ts +2195 -31
  66. package/lib/time-picker/time-picker.d.ts +839 -106
  67. package/lib/toggletip/toggletip.d.ts +10 -4
  68. package/lib/tooltip/tooltip.d.ts +10 -4
  69. package/lib/tree-item/tree-item.d.ts +12 -0
  70. package/lib/tree-view/tree-view.d.ts +6 -0
  71. package/lib/video-player/video-player.d.ts +6 -0
  72. package/lib/visually-hidden/definition.d.ts +4 -0
  73. package/lib/visually-hidden/visually-hidden.d.ts +3 -0
  74. package/lib/visually-hidden/visually-hidden.template.d.ts +3 -0
  75. package/locales/de-DE.cjs +33 -1
  76. package/locales/de-DE.js +33 -1
  77. package/locales/en-GB.cjs +33 -1
  78. package/locales/en-GB.js +33 -1
  79. package/locales/en-US.cjs +33 -1
  80. package/locales/en-US.js +33 -1
  81. package/locales/ja-JP.cjs +33 -1
  82. package/locales/ja-JP.js +33 -1
  83. package/locales/zh-CN.cjs +33 -1
  84. package/locales/zh-CN.js +33 -1
  85. package/menu/index.cjs +1 -1
  86. package/menu/index.js +1 -1
  87. package/nav/index.cjs +1 -1
  88. package/nav/index.js +1 -1
  89. package/nav-disclosure/index.cjs +1 -1
  90. package/nav-disclosure/index.js +1 -1
  91. package/nav-item/index.cjs +1 -1
  92. package/nav-item/index.js +1 -1
  93. package/note/index.cjs +1 -1
  94. package/note/index.js +1 -1
  95. package/number-field/index.cjs +1 -1
  96. package/number-field/index.js +1 -1
  97. package/option/index.cjs +1 -1
  98. package/option/index.js +1 -1
  99. package/package.json +1 -1
  100. package/pagination/index.cjs +1 -1
  101. package/pagination/index.js +1 -1
  102. package/popup/index.cjs +1 -1
  103. package/popup/index.js +1 -1
  104. package/progress/index.cjs +1 -1
  105. package/progress/index.js +1 -1
  106. package/progress-ring/index.cjs +1 -1
  107. package/progress-ring/index.js +1 -1
  108. package/radio/index.cjs +1 -1
  109. package/radio/index.js +1 -1
  110. package/radio-group/index.cjs +1 -1
  111. package/radio-group/index.js +1 -1
  112. package/range-slider/index.cjs +1 -1
  113. package/range-slider/index.js +1 -1
  114. package/rich-text-editor/index.cjs +1 -1
  115. package/rich-text-editor/index.js +1 -1
  116. package/searchable-select/index.cjs +1 -1
  117. package/searchable-select/index.js +1 -1
  118. package/select/index.cjs +1 -1
  119. package/select/index.js +1 -1
  120. package/selectable-box/index.cjs +1 -1
  121. package/selectable-box/index.js +1 -1
  122. package/shared/affix.cjs +13 -7
  123. package/shared/affix.js +13 -8
  124. package/shared/aria/delegates-aria.d.ts +6 -0
  125. package/shared/aria/host-semantics.d.ts +6 -0
  126. package/shared/breadcrumb-item.cjs +2 -5
  127. package/shared/breadcrumb-item.js +2 -5
  128. package/shared/button.cjs +13 -11
  129. package/shared/button.js +13 -11
  130. package/shared/calendar-picker.template.cjs +3 -3
  131. package/shared/calendar-picker.template.js +1 -1
  132. package/shared/char-count.cjs +92 -0
  133. package/shared/char-count.js +90 -0
  134. package/shared/definition.js +1 -1
  135. package/shared/definition10.js +1 -1
  136. package/shared/definition11.cjs +27 -44
  137. package/shared/definition11.js +28 -45
  138. package/shared/definition12.js +1 -1
  139. package/shared/definition13.js +1 -1
  140. package/shared/definition14.cjs +53 -22
  141. package/shared/definition14.js +54 -23
  142. package/shared/definition15.cjs +31 -36
  143. package/shared/definition15.js +30 -36
  144. package/shared/definition16.cjs +43 -63
  145. package/shared/definition16.js +42 -63
  146. package/shared/definition17.cjs +8 -4
  147. package/shared/definition17.js +8 -4
  148. package/shared/definition18.cjs +10 -14
  149. package/shared/definition18.js +9 -14
  150. package/shared/definition19.cjs +85 -100
  151. package/shared/definition19.js +75 -91
  152. package/shared/definition2.js +1 -1
  153. package/shared/definition20.cjs +15 -20
  154. package/shared/definition20.js +14 -20
  155. package/shared/definition21.cjs +22 -3
  156. package/shared/definition21.js +23 -4
  157. package/shared/definition22.cjs +4 -4
  158. package/shared/definition22.js +5 -5
  159. package/shared/definition23.cjs +5 -38
  160. package/shared/definition23.js +5 -37
  161. package/shared/definition24.cjs +2 -7
  162. package/shared/definition24.js +3 -8
  163. package/shared/definition25.js +1 -1
  164. package/shared/definition26.cjs +157 -171
  165. package/shared/definition26.js +156 -171
  166. package/shared/definition27.cjs +1 -1
  167. package/shared/definition27.js +2 -2
  168. package/shared/definition28.cjs +32 -17
  169. package/shared/definition28.js +33 -18
  170. package/shared/definition29.js +1 -1
  171. package/shared/definition3.js +1 -1
  172. package/shared/definition30.cjs +96 -482
  173. package/shared/definition30.js +99 -482
  174. package/shared/definition31.cjs +334 -57
  175. package/shared/definition31.js +333 -56
  176. package/shared/definition32.cjs +104 -19
  177. package/shared/definition32.js +105 -20
  178. package/shared/definition33.cjs +67 -15
  179. package/shared/definition33.js +66 -14
  180. package/shared/definition34.cjs +15 -50
  181. package/shared/definition34.js +14 -49
  182. package/shared/definition35.cjs +28 -397
  183. package/shared/definition35.js +27 -397
  184. package/shared/definition36.cjs +404 -54
  185. package/shared/definition36.js +404 -55
  186. package/shared/definition37.cjs +57 -234
  187. package/shared/definition37.js +57 -233
  188. package/shared/definition38.cjs +221 -66
  189. package/shared/definition38.js +220 -65
  190. package/shared/definition39.cjs +52 -44
  191. package/shared/definition39.js +51 -43
  192. package/shared/definition4.cjs +31 -24
  193. package/shared/definition4.js +33 -26
  194. package/shared/definition40.cjs +56 -266
  195. package/shared/definition40.js +55 -265
  196. package/shared/definition41.cjs +285 -142
  197. package/shared/definition41.js +285 -142
  198. package/shared/definition42.cjs +156 -564
  199. package/shared/definition42.js +156 -565
  200. package/shared/definition43.cjs +554 -14378
  201. package/shared/definition43.js +553 -14377
  202. package/shared/definition44.cjs +14418 -1155
  203. package/shared/definition44.js +14417 -1156
  204. package/shared/definition45.cjs +1049 -677
  205. package/shared/definition45.js +1050 -678
  206. package/shared/definition46.cjs +848 -113
  207. package/shared/definition46.js +847 -112
  208. package/shared/definition47.cjs +125 -90
  209. package/shared/definition47.js +124 -89
  210. package/shared/definition48.cjs +88 -455
  211. package/shared/definition48.js +87 -454
  212. package/shared/definition49.cjs +466 -109
  213. package/shared/definition49.js +466 -109
  214. package/shared/definition5.cjs +8 -7
  215. package/shared/definition5.js +6 -5
  216. package/shared/definition50.cjs +106 -106
  217. package/shared/definition50.js +105 -105
  218. package/shared/definition51.cjs +136 -15
  219. package/shared/definition51.js +135 -14
  220. package/shared/definition52.cjs +16 -115
  221. package/shared/definition52.js +15 -114
  222. package/shared/definition53.cjs +78 -412
  223. package/shared/definition53.js +77 -410
  224. package/shared/definition54.cjs +445 -23
  225. package/shared/definition54.js +443 -22
  226. package/shared/definition55.cjs +22 -136
  227. package/shared/definition55.js +21 -135
  228. package/shared/definition56.cjs +95 -291
  229. package/shared/definition56.js +95 -292
  230. package/shared/definition57.cjs +192 -480
  231. package/shared/definition57.js +190 -479
  232. package/shared/definition58.cjs +411 -24
  233. package/shared/definition58.js +410 -24
  234. package/shared/definition59.cjs +27 -144
  235. package/shared/definition59.js +27 -143
  236. package/shared/definition6.js +1 -1
  237. package/shared/definition60.cjs +83 -54
  238. package/shared/definition60.js +82 -53
  239. package/shared/definition61.cjs +78 -166
  240. package/shared/definition61.js +77 -164
  241. package/shared/definition62.cjs +143 -232
  242. package/shared/definition62.js +141 -231
  243. package/shared/definition63.cjs +234 -69417
  244. package/shared/definition63.js +233 -69416
  245. package/shared/definition64.cjs +69454 -28
  246. package/shared/definition64.js +69453 -27
  247. package/shared/definition65.cjs +28 -2168
  248. package/shared/definition65.js +27 -2166
  249. package/shared/definition66.cjs +27 -0
  250. package/shared/definition66.js +23 -0
  251. package/shared/definition67.cjs +2195 -0
  252. package/shared/definition67.js +2190 -0
  253. package/shared/definition7.cjs +11 -2
  254. package/shared/definition7.js +12 -3
  255. package/shared/definition8.cjs +24 -11
  256. package/shared/definition8.js +26 -13
  257. package/shared/definition9.cjs +1 -2
  258. package/shared/definition9.js +2 -3
  259. package/shared/delegates-aria.js +1 -1
  260. package/shared/deprecation/replaced-props.d.ts +20 -0
  261. package/shared/divider.cjs +41 -0
  262. package/shared/divider.js +38 -0
  263. package/shared/feedback/feedback-message.d.ts +345 -0
  264. package/shared/feedback/locale.d.ts +4 -0
  265. package/{lib/text-anchor/text-anchor.d.ts → shared/feedback/mixins.d.ts} +62 -39
  266. package/shared/form-associated.cjs +124 -100
  267. package/shared/form-associated.js +125 -101
  268. package/shared/form-element.cjs +84 -0
  269. package/shared/form-element.js +82 -0
  270. package/shared/foundation/button/button.d.ts +378 -2
  271. package/shared/foundation/form-associated/form-associated.d.ts +753 -49
  272. package/shared/foundation/listbox/listbox.d.ts +1 -1
  273. package/shared/foundation/vivid-element/vivid-element.d.ts +14 -0
  274. package/shared/host-semantics.js +1 -1
  275. package/shared/key-codes.js +1 -1
  276. package/shared/linkable.cjs +70 -0
  277. package/shared/linkable.js +68 -0
  278. package/shared/localization/Locale.d.ts +14 -0
  279. package/shared/mixins.cjs +306 -0
  280. package/shared/mixins.js +300 -0
  281. package/shared/patterns/affix.d.ts +16 -1
  282. package/shared/patterns/anchored.d.ts +20 -8
  283. package/shared/patterns/char-count/char-count.d.ts +351 -0
  284. package/shared/patterns/char-count/index.d.ts +1 -0
  285. package/shared/patterns/char-count/locale.d.ts +4 -0
  286. package/shared/patterns/form-elements/form-element.d.ts +744 -0
  287. package/shared/patterns/form-elements/index.d.ts +3 -1
  288. package/shared/patterns/form-elements/with-error-text.d.ts +1122 -0
  289. package/shared/patterns/form-elements/with-success-text.d.ts +341 -0
  290. package/shared/patterns/index.d.ts +2 -0
  291. package/shared/patterns/linkable.d.ts +394 -0
  292. package/shared/patterns/localized.d.ts +6 -0
  293. package/shared/patterns/trapped-focus.d.ts +6 -0
  294. package/shared/picker-field/mixins/calendar-picker.d.ts +420 -52
  295. package/shared/picker-field/mixins/calendar-picker.template.d.ts +420 -52
  296. package/shared/picker-field/mixins/inline-time-picker/inline-time-picker.d.ts +6 -0
  297. package/shared/picker-field/mixins/min-max-calendar-picker.d.ts +843 -107
  298. package/shared/picker-field/mixins/single-date-picker.d.ts +1259 -155
  299. package/shared/picker-field/mixins/single-value-picker.d.ts +417 -49
  300. package/shared/picker-field/mixins/time-selection-picker.d.ts +842 -106
  301. package/shared/picker-field/mixins/time-selection-picker.template.d.ts +839 -103
  302. package/shared/picker-field/picker-field.d.ts +1491 -15
  303. package/shared/picker-field.template.cjs +13 -22
  304. package/shared/picker-field.template.js +14 -23
  305. package/shared/repeat.js +1 -1
  306. package/shared/slider.template.cjs +1 -1
  307. package/shared/slider.template.js +1 -1
  308. package/shared/time-selection-picker.template.cjs +10 -15
  309. package/shared/time-selection-picker.template.js +10 -16
  310. package/shared/vivid-element.cjs +53 -4
  311. package/shared/vivid-element.js +53 -3
  312. package/shared/with-error-text.cjs +56 -0
  313. package/shared/with-error-text.js +54 -0
  314. package/shared/with-success-text.cjs +23 -0
  315. package/shared/with-success-text.js +21 -0
  316. package/side-drawer/index.cjs +1 -1
  317. package/side-drawer/index.js +1 -1
  318. package/slider/index.cjs +1 -1
  319. package/slider/index.js +1 -1
  320. package/split-button/index.cjs +1 -1
  321. package/split-button/index.js +1 -1
  322. package/styles/core/all.css +1 -1
  323. package/styles/core/theme.css +1 -1
  324. package/styles/core/typography.css +1 -1
  325. package/styles/tokens/theme-dark.css +4 -4
  326. package/styles/tokens/theme-light.css +4 -4
  327. package/styles/tokens/vivid-2-compat.css +1 -1
  328. package/switch/index.cjs +1 -1
  329. package/switch/index.js +1 -1
  330. package/tab/index.cjs +1 -1
  331. package/tab/index.js +1 -1
  332. package/tab-panel/index.cjs +1 -1
  333. package/tab-panel/index.js +1 -1
  334. package/tabs/index.cjs +1 -1
  335. package/tabs/index.js +1 -1
  336. package/tag/index.cjs +1 -1
  337. package/tag/index.js +1 -1
  338. package/tag-group/index.cjs +1 -1
  339. package/tag-group/index.js +1 -1
  340. package/text-area/index.cjs +1 -1
  341. package/text-area/index.js +1 -1
  342. package/text-field/index.cjs +1 -1
  343. package/text-field/index.js +1 -1
  344. package/time-picker/index.cjs +1 -1
  345. package/time-picker/index.js +1 -1
  346. package/toggletip/index.cjs +1 -1
  347. package/toggletip/index.js +1 -1
  348. package/tooltip/index.cjs +1 -1
  349. package/tooltip/index.js +1 -1
  350. package/tree-item/index.cjs +1 -1
  351. package/tree-item/index.js +1 -1
  352. package/tree-view/index.cjs +1 -1
  353. package/tree-view/index.js +1 -1
  354. package/video-player/index.cjs +1 -1
  355. package/video-player/index.js +1 -1
  356. package/visually-hidden/index.cjs +5 -0
  357. package/visually-hidden/index.js +3 -0
  358. package/vivid.api.json +744 -1490
  359. package/lib/checkbox/checkbox.form-associated.d.ts +0 -11
  360. package/lib/file-picker/file-picker.form-associated.d.ts +0 -11
  361. package/lib/number-field/number-field.form-associated.d.ts +0 -11
  362. package/lib/radio/radio.form-associated.d.ts +0 -13
  363. package/lib/range-slider/range-slider.form-associated.d.ts +0 -11
  364. package/lib/searchable-select/searchable-select.form-associated.d.ts +0 -11
  365. package/lib/select/select.form-associated.d.ts +0 -11
  366. package/lib/slider/slider.form-associated.d.ts +0 -11
  367. package/lib/switch/switch.form-associated.d.ts +0 -11
  368. package/lib/text-anchor/definition.d.ts +0 -2
  369. package/lib/text-anchor/text-anchor.template.d.ts +0 -3
  370. package/lib/text-area/text-area.form-associated.d.ts +0 -11
  371. package/lib/text-field/text-field.form-associated.d.ts +0 -11
  372. package/shared/anchor.cjs +0 -49
  373. package/shared/anchor.js +0 -47
  374. package/shared/apply-mixins.cjs +0 -23
  375. package/shared/apply-mixins.js +0 -21
  376. package/shared/applyMixinsWithObservables.cjs +0 -15
  377. package/shared/applyMixinsWithObservables.js +0 -13
  378. package/shared/direction.cjs +0 -17
  379. package/shared/direction.js +0 -15
  380. package/shared/form-elements.cjs +0 -209
  381. package/shared/form-elements.js +0 -202
  382. package/shared/foundation/anchor/anchor.d.ts +0 -11
  383. package/shared/foundation/utilities/apply-mixins.d.ts +0 -1
  384. package/shared/patterns/form-elements/form-elements.d.ts +0 -58
  385. package/shared/picker-field/picker-field.form-associated.d.ts +0 -11
  386. package/shared/text-anchor.cjs +0 -38
  387. package/shared/text-anchor.js +0 -36
  388. package/shared/text-anchor.template.cjs +0 -35
  389. package/shared/text-anchor.template.js +0 -33
  390. package/shared/utils/applyMixinsWithObservables.d.ts +0 -1
  391. package/text-anchor/index.cjs +0 -17
  392. package/text-anchor/index.js +0 -15
@@ -1,907 +1,1279 @@
1
1
  'use strict';
2
2
 
3
- const definition = require('./definition65.cjs');
4
- const definition$2 = require('./definition28.cjs');
5
- const definition$3 = require('./definition36.cjs');
3
+ const definition$1 = require('./definition11.cjs');
4
+ const definition = require('./definition67.cjs');
5
+ const definition$3 = require('./definition28.cjs');
6
+ const definition$2 = require('./definition39.cjs');
6
7
  const vividElement = require('./vivid-element.cjs');
7
- const applyMixinsWithObservables = require('./applyMixinsWithObservables.cjs');
8
- const listbox = require('./listbox.cjs');
9
- const hostSemantics = require('./host-semantics.cjs');
8
+ const mixins = require('./mixins.cjs');
9
+ const scrollIntoView = require('./scrollIntoView.cjs');
10
+ const delegatesAria = require('./delegates-aria.cjs');
10
11
  const formAssociated = require('./form-associated.cjs');
11
- const numbers = require('./numbers.cjs');
12
+ const withErrorText = require('./with-error-text.cjs');
13
+ const withSuccessText = require('./with-success-text.cjs');
14
+ const formElement = require('./form-element.cjs');
12
15
  const affix = require('./affix.cjs');
13
- const strings = require('./strings.cjs');
14
- const keyCodes = require('./key-codes.cjs');
15
- const formElements = require('./form-elements.cjs');
16
+ const localized = require('./localized.cjs');
16
17
  const option = require('./option.cjs');
17
- const definition$1 = require('./definition11.cjs');
18
- const index = require('./index.cjs');
19
- const ref = require('./ref.cjs');
20
18
  const when = require('./when.cjs');
19
+ const ref = require('./ref.cjs');
21
20
  const slotted = require('./slotted.cjs');
22
21
  const classNames = require('./class-names.cjs');
22
+ const repeat = require('./repeat.cjs');
23
23
 
24
- const styles = ".chevron{display:flex;flex-shrink:0;font:var(--vvd-typography-base-extended);transform:rotate(0);transition:transform .2s}:host([aria-expanded=true]) .chevron,:host([open]) .chevron{transform:rotate(180deg)}:host(:focus-visible){outline:none}:host{display:inline-flex;flex-direction:column;gap:4px;--_low-ink-color: var(--vvd-color-neutral-600);--focus-stroke-gap-color: transparent}:host([disabled]){--_low-ink-color: var(--vvd-color-neutral-400);cursor:not-allowed}.label{color:var(--vvd-color-canvas-text);contain:inline-size;font:var(--vvd-typography-base)}.control{--_appearance-color-text: var(--vvd-color-canvas-text);--_appearance-color-fill: var(--vvd-color-canvas);--_appearance-color-outline: var(--vvd-color-neutral-500)}.control.appearance-ghost{--_appearance-color-text: var(--_connotation-color-firm);--_appearance-color-fill: transparent;--_appearance-color-outline: transparent}.control:where(.hover,:hover):where(:not(.disabled,:disabled,.readonly)){--_appearance-color-text: var(--vvd-color-canvas-text);--_appearance-color-fill: var(--vvd-color-canvas);--_appearance-color-outline: var(--vvd-color-neutral-700)}.control:where(.hover,:hover):where(:not(.disabled,:disabled,.readonly)).appearance-ghost{--_appearance-color-text: var(--_connotation-color-firm);--_appearance-color-fill: var(--_connotation-color-faint);--_appearance-color-outline: transparent}.control:where(.disabled,:disabled){--_appearance-color-text: var(--vvd-color-neutral-300);--_appearance-color-fill: var(--vvd-color-neutral-100);--_appearance-color-outline: var(--vvd-color-neutral-300)}.control:where(.disabled,:disabled).appearance-ghost{--_appearance-color-text: var(--vvd-color-neutral-300);--_appearance-color-fill: transparent;--_appearance-color-outline: transparent}.control:where(.readonly):where(:not(.disabled,:disabled)){--_appearance-color-text: var(--vvd-color-canvas-text);--_appearance-color-fill: var(--vvd-color-neutral-200);--_appearance-color-outline: var(--vvd-color-neutral-400)}.control:where(.readonly):where(:not(.disabled,:disabled)).appearance-ghost{--_appearance-color-text: var(--vvd-color-neutral-600);--_appearance-color-fill: transparent;--_appearance-color-outline: transparent}.control:where(.error):where(:not(.disabled,:disabled)){--_appearance-color-text: notSet;--_appearance-color-fill: var(--vvd-color-alert-50);--_appearance-color-outline: var(--vvd-color-alert-500)}.control:where(.error):where(:not(.disabled,:disabled)).appearance-ghost{--_appearance-color-text: notSet;--_appearance-color-fill: var(--vvd-color-alert-50);--_appearance-color-outline: transparent}.control:where(.success):where(:not(.disabled,:disabled)){--_appearance-color-text: notSet;--_appearance-color-fill: var(--vvd-color-success-50);--_appearance-color-outline: var(--vvd-color-success-500)}.control:where(.success):where(:not(.disabled,:disabled)).appearance-ghost{--_appearance-color-text: notSet;--_appearance-color-fill: var(--vvd-color-success-50);--_appearance-color-outline: transparent}.control{--_connotation-color-primary: var(--vvd-select-accent-primary, var(--vvd-color-canvas-text));--_connotation-color-primary-text: var(--vvd-select-accent-primary-text, var(--vvd-color-canvas));--_connotation-color-primary-increment: var(--vvd-select-accent-primary-increment, var(--vvd-color-neutral-800));--_connotation-color-intermediate: var(--vvd-select-accent-intermediate, var(--vvd-color-neutral-500));--_connotation-color-faint: var(--vvd-select-accent-faint, var(--vvd-color-neutral-50));--_connotation-color-soft: var(--vvd-select-accent-soft, var(--vvd-color-neutral-100));--_connotation-color-firm: var(--vvd-select-accent-firm, var(--vvd-color-canvas-text));--_connotation-color-fierce: var(--vvd-select-accent-fierce, var(--vvd-color-neutral-700))}.control{border-radius:var(--_select-control-border-radius);block-size:var(--_select-block-size);padding-inline:var(--_select-padding-inline)}.control{--_select-icon-size: calc(1px*(40 + 4*clamp(-1, var(--vvd-size-density, 0), 2))/2) ;--_select-block-size: calc(1px*(40 + 4*clamp(-1, var(--vvd-size-density, 0), 2))) ;--_select-padding-inline: calc(1px*(40 + 4*clamp(-1, var(--vvd-size-density, 0), 2))*.4) ;display:flex;align-items:center;justify-content:space-between;background-color:var(--_appearance-color-fill);box-shadow:inset 0 0 0 1px var(--_appearance-color-outline);color:var(--_appearance-color-text);font:var(--vvd-typography-base);gap:8px;transition:box-shadow .2s,background-color .2s}.control.size-condensed{--_select-icon-size: calc(1px*(40 + 4*clamp(-1, var(--vvd-size-density, 0), 2))*.4) ;--_select-block-size: calc(1px*(32 + 4*clamp(-1, var(--vvd-size-density, 0), 2))) ;--_select-padding-inline: calc(1px*(24 + 4*clamp(-1, var(--vvd-size-density, 0), 2))/2) }.control.size-condensed:not(.shape-pill){--_select-control-border-radius: 4px}.control-wrapper{position:relative}.control:not(.disabled){cursor:pointer}.control.disabled{pointer-events:none}.control:not(.shape-pill){--_select-control-border-radius: 8px}.control.shape-pill{--_select-control-border-radius: 24px}:host(:focus-visible) .control{box-shadow:0 0 0 4px color-mix(in srgb,var(--vvd-color-cta-500),transparent 85%),inset 0 0 0 3px var(--focus-stroke-gap-color, currentColor);outline:1px solid var(--focus-stroke-color, var(--vvd-color-cta-500));outline-offset:calc(-1px - var(--focus-inset, 0px))}.listbox{display:flex;max-height:var(--select-height, 408px);flex-direction:column;padding:4px;gap:2px;overflow-y:auto}:host([multiple]:focus-visible) .listbox{box-shadow:0 0 0 4px color-mix(in srgb,var(--vvd-color-cta-500),transparent 85%),inset 0 0 0 3px var(--focus-stroke-gap-color, currentColor);outline:1px solid var(--focus-stroke-color, var(--vvd-color-cta-500));outline-offset:calc(-1px - var(--focus-inset, 0px));border-radius:8px}.selected-value{display:flex;overflow:hidden;flex-grow:1;align-items:center;column-gap:12px;white-space:nowrap}.selected-value .text{overflow:hidden;max-inline-size:100%;text-overflow:ellipsis}.control.shows-placeholder .selected-value .text{color:var(--vvd-color-neutral-600)}.selected-value slot[name=icon]{flex:0 0 var(--_select-icon-size);font-size:var(--_select-icon-size);line-height:1}.control.has-meta .selected-value{padding-inline-end:8px}.feedback-wrapper{display:contents}::part(popup-base){inline-size:max-content;min-inline-size:var(--_select-fixed-width, 100%)}:host([multiple]) ::part(popup-base){position:static}";
24
+ const styles = ".chevron{display:flex;flex-shrink:0;font:var(--vvd-typography-base-extended);transform:rotate(0);transition:transform .2s}:host([data-expanded=true]) .chevron,:host([open]) .chevron{transform:rotate(180deg)}:not(.disabled) .chevron{cursor:pointer}.disabled .chevron{color:var(--_low-ink-color);cursor:not-allowed}:host(:focus-visible){outline:none}:host{display:inline-block;inline-size:300px;--_low-ink-color: var(--vvd-color-neutral-600)}:host([disabled]){--_low-ink-color: var(--vvd-color-neutral-400);cursor:not-allowed}.control-wrapper{display:flex;flex-direction:column;gap:4px}.label{color:var(--vvd-color-canvas-text);font:var(--vvd-typography-base)}.selection-count{color:var(--_low-ink-color);font:var(--vvd-typography-base)}.fieldset{--_connotation-color-primary: var(--vvd-searchable-select-accent-primary, var(--vvd-color-canvas-text));--_connotation-color-primary-text: var(--vvd-searchable-select-accent-primary-text, var(--vvd-color-canvas));--_connotation-color-primary-increment: var(--vvd-searchable-select-accent-primary-increment, var(--vvd-color-neutral-800));--_connotation-color-intermediate: var(--vvd-searchable-select-accent-intermediate, var(--vvd-color-neutral-500));--_connotation-color-faint: var(--vvd-searchable-select-accent-faint, var(--vvd-color-neutral-50));--_connotation-color-soft: var(--vvd-searchable-select-accent-soft, var(--vvd-color-neutral-100));--_connotation-color-firm: var(--vvd-searchable-select-accent-firm, var(--vvd-color-canvas-text));--_connotation-color-fierce: var(--vvd-searchable-select-accent-fierce, var(--vvd-color-neutral-700))}.fieldset{--_appearance-color-text: var(--vvd-color-canvas-text);--_appearance-color-fill: var(--vvd-color-canvas);--_appearance-color-outline: var(--vvd-color-neutral-500)}.fieldset.appearance-ghost{--_appearance-color-text: var(--_connotation-color-firm);--_appearance-color-fill: transparent;--_appearance-color-outline: transparent}.fieldset:where(.hover,:hover):where(:not(.disabled,:disabled,.readonly)){--_appearance-color-text: var(--vvd-color-canvas-text);--_appearance-color-fill: var(--vvd-color-canvas);--_appearance-color-outline: var(--vvd-color-neutral-700)}.fieldset:where(.hover,:hover):where(:not(.disabled,:disabled,.readonly)).appearance-ghost{--_appearance-color-text: var(--_connotation-color-firm);--_appearance-color-fill: var(--_connotation-color-faint);--_appearance-color-outline: transparent}.fieldset:where(.disabled,:disabled){--_appearance-color-text: var(--vvd-color-neutral-300);--_appearance-color-fill: var(--vvd-color-neutral-100);--_appearance-color-outline: var(--vvd-color-neutral-300)}.fieldset:where(.disabled,:disabled).appearance-ghost{--_appearance-color-text: var(--vvd-color-neutral-300);--_appearance-color-fill: transparent;--_appearance-color-outline: transparent}.fieldset:where(.readonly):where(:not(.disabled,:disabled)){--_appearance-color-text: var(--vvd-color-canvas-text);--_appearance-color-fill: var(--vvd-color-neutral-200);--_appearance-color-outline: var(--vvd-color-neutral-400)}.fieldset:where(.readonly):where(:not(.disabled,:disabled)).appearance-ghost{--_appearance-color-text: var(--vvd-color-neutral-600);--_appearance-color-fill: transparent;--_appearance-color-outline: transparent}.fieldset:where(.error):where(:not(.disabled,:disabled)){--_appearance-color-text: notSet;--_appearance-color-fill: var(--vvd-color-alert-50);--_appearance-color-outline: var(--vvd-color-alert-500)}.fieldset:where(.error):where(:not(.disabled,:disabled)).appearance-ghost{--_appearance-color-text: notSet;--_appearance-color-fill: var(--vvd-color-alert-50);--_appearance-color-outline: transparent}.fieldset:where(.success):where(:not(.disabled,:disabled)){--_appearance-color-text: notSet;--_appearance-color-fill: var(--vvd-color-success-50);--_appearance-color-outline: var(--vvd-color-success-500)}.fieldset:where(.success):where(:not(.disabled,:disabled)).appearance-ghost{--_appearance-color-text: notSet;--_appearance-color-fill: var(--vvd-color-success-50);--_appearance-color-outline: transparent}.fieldset{display:flex;align-items:center;justify-content:space-between;background-color:var(--_appearance-color-fill);box-shadow:inset 0 0 0 1px var(--_appearance-color-outline);color:var(--_appearance-color-text);font:var(--vvd-typography-base);gap:8px;padding-block:8px;padding-inline:16px;transition:box-shadow .2s,background-color .2s}.fieldset:focus-within{box-shadow:0 0 0 4px color-mix(in srgb,var(--vvd-color-cta-500),transparent 85%),inset 0 0 0 3px var(--focus-stroke-gap-color, currentColor);outline:1px solid var(--focus-stroke-color, var(--vvd-color-cta-500));outline-offset:calc(-1px - var(--focus-inset, 0px));--focus-stroke-gap-color: transparent}:host(:not([shape=pill])) .fieldset{border-radius:8px}:host([shape=pill]) .fieldset{border-radius:24px}.popup-wrapper{position:relative}.content-area{display:flex;overflow:hidden;flex:1;flex-direction:column;gap:8px;min-block-size:24px}.tag-row{display:flex;gap:8px;inline-size:100%}.tag-row.contains-only-input:not(:focus-within){display:contents}.tag-wrapper{overflow:hidden}.tag{max-inline-size:100%}input{box-sizing:border-box;flex:1;border:none;background:none;block-size:24px;font:var(--vvd-typography-base);max-inline-size:100%;min-inline-size:100px;outline:none}.contains-only-input input:not(:focus){position:absolute;block-size:0;inline-size:0;min-inline-size:0;opacity:0;pointer-events:none}.listbox{display:flex;flex-direction:column;padding:4px;gap:2px;max-block-size:var(--searchable-select-height, 408px);overflow-y:auto}.empty-message{display:flex;align-items:center;justify-content:center;color:var(--vvd-color-neutral-300);font:var(--vvd-typography-base);min-block-size:40px;text-align:center}::part(popup-base){inline-size:max-content;min-inline-size:var(--_searchable-select-fixed-width, 100%)}slot[name=icon]{font-size:20px}.visually-hidden{position:absolute;overflow:hidden;width:1px;height:1px;clip:rect(0 0 0 0);clip-path:inset(50%);white-space:nowrap}";
25
25
 
26
- class _Select extends listbox.Listbox {
27
- }
28
- class FormAssociatedSelect extends formAssociated.FormAssociated(_Select) {
29
- constructor() {
30
- super(...arguments);
31
- this.proxy = document.createElement("select");
32
- }
33
- }
26
+ const optionTagStyles = ".base.connotation-cta{--_connotation-color-contrast: var(--vvd-option-tag-cta-contrast, var(--vvd-color-cta-800))}.base:not(.connotation-cta){--_connotation-color-contrast: var(--vvd-option-tag-accent-contrast, var(--vvd-color-neutral-800))}.base{position:relative;display:inline-flex;box-sizing:border-box;align-items:center;background-color:var(--fill-color);block-size:calc(1px*(24 + 4*clamp(-1,var(--vvd-size-density, 0),2)));box-shadow:inset 0 0 0 1px var(--outline-color);color:var(--text-color);column-gap:8px;font:var(--vvd-typography-base-bold);max-inline-size:100%;padding-inline:8px;user-select:none;vertical-align:middle}.base:not(.disabled){--text-color: var(--_connotation-color-contrast);--fill-color: color-mix( in srgb, var(--_connotation-color-contrast), transparent 87.5% );--outline-color: transparent}.base.disabled{--text-color: var(--vvd-color-neutral-300);--fill-color: color-mix( in srgb, var(--vvd-color-neutral-800), transparent 87.5% );--outline-color: transparent}.base:not(.shape-pill){border-radius:4px}.base.shape-pill{border-radius:16px}.label{overflow:hidden;max-inline-size:100%;text-overflow:ellipsis;white-space:nowrap}slot[name=icon]{font-size:calc(calc(1px*(24 + 4*clamp(-1,var(--vvd-size-density, 0),2))) / 1.5);line-height:1}.icon-placeholder{inline-size:calc(calc(1px*(24 + 4*clamp(-1,var(--vvd-size-density, 0),2))) / 1.5)}.remove-button{display:flex;align-items:center;border-radius:inherit;cursor:pointer;outline:none}.disabled .remove-button{pointer-events:none}.remove-button:focus-visible:before{--focus-stroke-gap-color: transparent;box-shadow:0 0 0 4px color-mix(in srgb,var(--vvd-color-cta-500),transparent 85%),inset 0 0 0 3px var(--focus-stroke-gap-color, currentColor);outline:1px solid var(--focus-stroke-color, var(--vvd-color-cta-500));outline-offset:calc(-1px - var(--focus-inset, 0px));position:absolute;z-index:1;display:block;border-radius:inherit;content:\"\";inset:0;pointer-events:none}";
34
27
 
35
- var __defProp = Object.defineProperty;
36
- var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
37
- var __decorateClass = (decorators, target, key, kind) => {
38
- var result = kind > 1 ? void 0 : kind ? __getOwnPropDesc(target, key) : target;
28
+ var __defProp$1 = Object.defineProperty;
29
+ var __decorateClass$1 = (decorators, target, key, kind) => {
30
+ var result = void 0 ;
39
31
  for (var i = decorators.length - 1, decorator; i >= 0; i--)
40
32
  if (decorator = decorators[i])
41
- result = (kind ? decorator(target, key, result) : decorator(result)) || result;
42
- if (kind && result) __defProp(target, key, result);
33
+ result = (decorator(target, key, result) ) || result;
34
+ if (result) __defProp$1(target, key, result);
43
35
  return result;
44
36
  };
45
- exports.Select = class Select extends hostSemantics.HostSemantics(
46
- affix.AffixIconWithTrailing(FormAssociatedSelect)
37
+ const TagGapPx = 8;
38
+ const InputMinWidthPx = 100;
39
+ const PageSize = 10;
40
+ const isFormAssociatedTryingToSetFormValue = (value) => typeof value === "string";
41
+ class SearchableSelect extends mixins.WithFeedback(
42
+ withErrorText.WithErrorText(
43
+ withSuccessText.WithSuccessText(
44
+ formElement.FormElement(
45
+ delegatesAria.DelegatesAria(
46
+ affix.AffixIconWithTrailing(localized.Localized(formAssociated.FormAssociated(vividElement.VividElement)))
47
+ )
48
+ )
49
+ )
50
+ )
47
51
  ) {
48
52
  constructor() {
49
53
  super(...arguments);
50
- this.activeIndex = -1;
54
+ this.fixedDropdown = false;
55
+ this.open = false;
56
+ this.multiple = false;
57
+ this.externalTags = false;
58
+ this.maxLines = null;
59
+ this.values = [];
60
+ this.initialValues = [];
61
+ this._currentSearchText = null;
62
+ // --- Slotted options ---
51
63
  /**
52
- * The start index when checking a range of options.
53
- *
54
64
  * @internal
55
65
  */
56
- this.rangeStartIndex = -1;
57
- this.open = false;
66
+ this._areOptionsInitialized = false;
67
+ this.#slottedOptionsChangeHandler = {
68
+ handleChange: (source, _) => {
69
+ if (source.selected && !this.values.includes(source.value)) {
70
+ this.values = [...this.values, source.value];
71
+ } else if (!source.selected && this.values.includes(source.value)) {
72
+ this.values = this.values.filter((option) => option !== source.value);
73
+ }
74
+ }
75
+ };
76
+ // --- Option tag icons ---
77
+ this.#clonedTagIcons = /* @__PURE__ */ new Map();
78
+ this._filteredOptions = [];
79
+ this._filteredEnabledOptions = [];
80
+ this.loading = false;
81
+ this._highlightedOptionIndex = null;
82
+ this._numElidedTags = 0;
83
+ this._tagRows = [];
84
+ this._lastTagRow = [];
85
+ this.clearable = false;
86
+ this.maxSelected = null;
87
+ this._slottedDisabledOptions = [];
88
+ // --- Form handling ---
58
89
  /**
59
- * The unique id for the internal listbox element.
60
- *
61
90
  * @internal
62
91
  */
63
- this.listboxId = strings.uniqueId("listbox-");
64
- this.maxHeight = 0;
65
- this.fixedDropdown = false;
66
- this.placeholderOption = null;
67
- this._feedbackWrapper = null;
92
+ this.proxy = document.createElement("input");
93
+ this.setFormValue = (value, state) => {
94
+ if (isFormAssociatedTryingToSetFormValue(value)) {
95
+ return;
96
+ }
97
+ super.setFormValue(value, state);
98
+ };
99
+ this._changeDescription = "";
100
+ // --- Core ---
101
+ this.#resizeObserver = new ResizeObserver(() => {
102
+ this.#updateTagLayout();
103
+ });
68
104
  }
69
105
  /**
70
- * Returns the last checked option.
71
- *
72
106
  * @internal
73
107
  */
74
- get activeOption() {
75
- return this.options[this.activeIndex];
108
+ openChanged() {
109
+ if (!this.open) {
110
+ this.#transitionHighlightedOptionTo(null);
111
+ }
76
112
  }
77
113
  /**
78
- * Returns the list of checked options.
79
- *
80
114
  * @internal
81
115
  */
82
- get checkedOptions() {
83
- return this.options.filter((o) => o.checked);
116
+ valuesChanged() {
117
+ if (!this._areOptionsInitialized) {
118
+ return;
119
+ }
120
+ if (!this.multiple && this.values.length > 1) {
121
+ this.values = [this.values[0]];
122
+ return;
123
+ }
124
+ if (this.values.some((value) => !this.#isValidValue(value))) {
125
+ this.values = this.values.filter((value) => this.#isValidValue(value));
126
+ return;
127
+ }
128
+ this.value = this.values.length ? this.values[0] : "";
129
+ this.#updateSelectionLimit();
130
+ this.#updateSelectedOnSlottedOptions();
131
+ if (this.$fastController.isConnected) {
132
+ this.#updateTagLayout();
133
+ }
134
+ this.#updateFormValue();
84
135
  }
85
- /**
86
- * Returns the index of the first selected option.
87
- *
88
- * @internal
89
- */
90
- get firstSelectedOptionIndex() {
91
- return this.options.indexOf(this.firstSelectedOption);
136
+ #updateValuesThroughUserInteraction(newValues) {
137
+ this.values = newValues;
138
+ this.$emit("change", void 0, {
139
+ bubbles: false
140
+ });
141
+ this.$emit("input", void 0, {
142
+ bubbles: false
143
+ });
92
144
  }
93
- /**
94
- * Updates the `ariaActiveDescendant` property when the active index changes.
95
- *
96
- * @internal
97
- */
98
- activeIndexChanged(_, next) {
99
- this._activeDescendant = this.options[next]?.id ?? "";
100
- this.focusAndScrollOptionIntoView();
145
+ #updateValuesWhileMaintainingOrder(newValues) {
146
+ const oldSet = new Set(this.values);
147
+ const newSet = new Set(newValues);
148
+ this.values = [...this.values].filter((v) => newSet.has(v)).concat([...newValues].filter((v) => !oldSet.has(v)));
101
149
  }
102
150
  /**
103
- * Toggles the checked state for the currently active option.
104
- *
105
- * @remarks
106
- * Multiple-selection mode only.
107
- *
108
151
  * @internal
109
152
  */
110
- checkActiveIndex() {
111
- const activeItem = this.activeOption;
112
- if (activeItem) {
113
- activeItem.checked = true;
153
+ initialValuesChanged() {
154
+ if (!this.dirtyValue) {
155
+ this.values = this.initialValues;
156
+ this.dirtyValue = false;
114
157
  }
115
158
  }
159
+ #isValidValue(value) {
160
+ return this._slottedOptions.some((option) => option.value === value);
161
+ }
116
162
  /**
117
- * Sets the active index to the first option and marks it as checked.
118
- *
119
- * @remarks
120
- * Multi-selection mode only.
121
- *
122
- * @param preserveChecked - mark all options unchecked before changing the active index
123
- *
124
163
  * @internal
125
164
  */
126
- checkFirstOption(preserveChecked) {
127
- if (preserveChecked) {
128
- if (this.rangeStartIndex === -1) {
129
- this.rangeStartIndex = this.activeIndex + 1;
130
- }
131
- this.options.forEach((o, i) => {
132
- o.checked = numbers.inRange(i, this.rangeStartIndex);
133
- });
165
+ valueChanged(prev, next) {
166
+ super.valueChanged(prev, next);
167
+ if (!this._areOptionsInitialized) {
168
+ return;
169
+ }
170
+ const isValidValue = this._slottedOptions.some(
171
+ (option) => option.value === next
172
+ );
173
+ if (this.values[0] !== next) {
174
+ this.values = isValidValue ? [next] : [];
175
+ }
176
+ }
177
+ get selectedIndex() {
178
+ if (this.values.length) {
179
+ return this._slottedOptions.findIndex(
180
+ (option) => option.value === this.values[0]
181
+ );
134
182
  } else {
135
- this.uncheckAllOptions();
183
+ return -1;
136
184
  }
137
- this.activeIndex = 0;
138
- this.checkActiveIndex();
185
+ }
186
+ set selectedIndex(index) {
187
+ this.value = this._slottedOptions[index]?.value ?? "";
188
+ }
189
+ get options() {
190
+ return [...this._slottedOptions];
191
+ }
192
+ get selectedOptions() {
193
+ return this._slottedOptions.filter(
194
+ (option) => this.values.includes(option.value)
195
+ );
139
196
  }
140
197
  /**
141
- * Decrements the active index and sets the matching option as checked.
142
- *
143
- * @remarks
144
- * Multi-selection mode only.
145
- *
146
- * @param preserveChecked - mark all options unchecked before changing the active index
147
- *
148
198
  * @internal
149
199
  */
150
- checkLastOption(preserveChecked) {
151
- if (preserveChecked) {
152
- if (this.rangeStartIndex === -1) {
153
- this.rangeStartIndex = this.activeIndex;
154
- }
155
- this.options.forEach((o, i) => {
156
- o.checked = numbers.inRange(i, this.rangeStartIndex, this.length);
157
- });
158
- } else {
159
- this.uncheckAllOptions();
160
- }
161
- this.activeIndex = this.length - 1;
162
- this.checkActiveIndex();
200
+ _currentSearchTextChanged() {
201
+ this.#updateFilteredOptions();
202
+ this.$emit("search-text-change", void 0, {
203
+ bubbles: false,
204
+ composed: false
205
+ });
163
206
  }
164
207
  /**
165
- * Increments the active index and marks the matching option as checked.
166
- *
167
- * @remarks
168
- * Multiple-selection mode only.
169
- *
170
- * @param preserveChecked - mark all options unchecked before changing the active index
171
- *
172
- * @internal
208
+ * The current search text of the component.
173
209
  */
174
- checkNextOption(preserveChecked) {
175
- if (preserveChecked) {
176
- if (this.rangeStartIndex === -1) {
177
- this.rangeStartIndex = this.activeIndex;
178
- }
179
- this.options.forEach((o, i) => {
180
- o.checked = numbers.inRange(i, this.rangeStartIndex, this.activeIndex + 1);
181
- });
182
- } else {
183
- this.uncheckAllOptions();
184
- }
185
- this.activeIndex += this.activeIndex < this.length - 1 ? 1 : 0;
186
- this.checkActiveIndex();
210
+ get searchText() {
211
+ return this._currentSearchText ?? "";
187
212
  }
188
213
  /**
189
- * Decrements the active index and marks the matching option as checked.
190
- *
191
- * @remarks
192
- * Multiple-selection mode only.
193
- *
194
- * @param preserveChecked - mark all options unchecked before changing the active index
195
- *
196
214
  * @internal
197
215
  */
198
- checkPreviousOption(preserveChecked) {
199
- if (preserveChecked) {
200
- if (this.rangeStartIndex === -1) {
201
- this.rangeStartIndex = this.activeIndex;
202
- }
203
- if (this.checkedOptions.length === 1) {
204
- this.rangeStartIndex += 1;
205
- }
206
- this.options.forEach((o, i) => {
207
- o.checked = numbers.inRange(i, this.activeIndex, this.rangeStartIndex);
208
- });
209
- } else {
210
- this.uncheckAllOptions();
211
- }
212
- this.activeIndex -= this.activeIndex > 0 ? 1 : 0;
213
- this.checkActiveIndex();
216
+ get _inputValue() {
217
+ return this._currentSearchText ?? (!this.multiple && this.value !== "" ? this.#textForValue(this.value) ?? "" : "");
214
218
  }
215
219
  /**
216
220
  * @internal
217
221
  */
218
- focusAndScrollOptionIntoView() {
219
- super.focusAndScrollOptionIntoView(this.activeOption);
222
+ _onInputInput(event) {
223
+ this._currentSearchText = event.target.value;
220
224
  }
221
225
  /**
222
- * In multiple-selection mode:
223
- * If any options are selected, the first selected option is checked when
224
- * the listbox receives focus. If no options are selected, the first
225
- * selectable option is checked.
226
- *
227
226
  * @internal
228
227
  */
229
- focusinHandler(e) {
230
- if (!this.multiple) {
231
- return super.focusinHandler(e);
232
- }
233
- if (!this.shouldSkipFocus && e.target === e.currentTarget) {
234
- this.uncheckAllOptions();
235
- if (this.activeIndex === -1) {
236
- this.activeIndex = this.firstSelectedOptionIndex !== -1 ? this.firstSelectedOptionIndex : 0;
237
- }
238
- this.checkActiveIndex();
239
- this.setSelectedOptions();
240
- this.focusAndScrollOptionIntoView();
241
- }
242
- this.shouldSkipFocus = false;
228
+ _onInputFocus(_) {
229
+ this.#updateFilteredOptions();
230
+ this.open = true;
243
231
  }
244
232
  /**
245
- * Sets an option as selected and gives it focus.
246
- *
247
- * @public
233
+ * @internal
248
234
  */
249
- setSelectedOptions() {
250
- if (!this.multiple) {
251
- super.setSelectedOptions();
252
- return;
253
- }
254
- if (this.$fastController.isConnected && this.options) {
255
- this.selectedOptions = this.options.filter((o) => o.selected);
256
- this.focusAndScrollOptionIntoView();
257
- }
235
+ _onInputBlur(_) {
236
+ this.open = false;
237
+ this._currentSearchText = null;
238
+ this._changeDescription = "";
258
239
  }
259
240
  /**
260
- * Toggles the selected state of the provided options. If any provided items
261
- * are in an unselected state, all items are set to selected. If every
262
- * provided item is selected, they are all unselected.
263
- *
264
241
  * @internal
265
242
  */
266
- toggleSelectedForAllCheckedOptions() {
267
- const enabledCheckedOptions = this.checkedOptions.filter(
268
- (o) => !o.disabled
269
- );
270
- const force = !enabledCheckedOptions.every((o) => o.selected);
271
- enabledCheckedOptions.forEach((o) => o.selected = force);
272
- this.selectedIndex = this.options.indexOf(
273
- enabledCheckedOptions[enabledCheckedOptions.length - 1]
274
- );
275
- this.setSelectedOptions();
276
- this.updateValue(true);
243
+ _onInputKeydown(e) {
244
+ if (e.ctrlKey || e.shiftKey) {
245
+ return true;
246
+ }
247
+ switch (e.key) {
248
+ case "Enter":
249
+ this.#selectHighlightedOption();
250
+ return false;
251
+ case "Escape":
252
+ this.open = false;
253
+ break;
254
+ case "Home":
255
+ if (!this.open) {
256
+ this.open = true;
257
+ break;
258
+ }
259
+ this.#highlightFirstOption();
260
+ return false;
261
+ case "End":
262
+ if (!this.open) {
263
+ this.open = true;
264
+ break;
265
+ }
266
+ this.#highlightLastOption();
267
+ return false;
268
+ case "PageUp":
269
+ if (!this.open) {
270
+ this.open = true;
271
+ break;
272
+ }
273
+ this.#highlightPrevPage();
274
+ return false;
275
+ case "PageDown":
276
+ if (!this.open) {
277
+ this.open = true;
278
+ break;
279
+ }
280
+ this.#highlightNextPage();
281
+ return false;
282
+ case "ArrowUp":
283
+ if (!this.open) {
284
+ this.open = true;
285
+ break;
286
+ }
287
+ this.#highlightPreviousOption();
288
+ return false;
289
+ case "ArrowDown":
290
+ if (!this.open) {
291
+ this.open = true;
292
+ break;
293
+ }
294
+ this.#highlightNextOption();
295
+ return false;
296
+ case "ArrowLeft":
297
+ if (this.multiple && this._inputValue === "" && this.values.length && !this.externalTags) {
298
+ this.#moveTagFocusTo(this.#nextTagIndexLeft(this.values.length));
299
+ return false;
300
+ }
301
+ return true;
302
+ case "Backspace":
303
+ if (this.multiple && this._inputValue === "" && this.values.length) {
304
+ this._onTagRemoved(this.values[this.values.length - 1]);
305
+ return false;
306
+ }
307
+ return true;
308
+ default:
309
+ if (!this.open) {
310
+ this.open = true;
311
+ }
312
+ return true;
313
+ }
314
+ return true;
277
315
  }
278
316
  /**
279
317
  * @internal
280
318
  */
281
- typeaheadBufferChanged(prev, next) {
282
- if (!this.multiple) {
283
- super.typeaheadBufferChanged(prev, next);
319
+ _slottedOptionsChanged(oldValue, newValue) {
320
+ const hasSlottedOptions = Boolean(
321
+ this.querySelectorAll(`:not([slot])`).length
322
+ );
323
+ if (!newValue.length && hasSlottedOptions) {
284
324
  return;
285
325
  }
286
- if (this.$fastController.isConnected) {
287
- const typeaheadMatches = this.getTypeaheadMatches();
288
- const activeIndex = this.options.indexOf(typeaheadMatches[0]);
289
- if (activeIndex > -1) {
290
- this.activeIndex = activeIndex;
291
- this.uncheckAllOptions();
292
- this.checkActiveIndex();
326
+ this._areOptionsInitialized = true;
327
+ if (oldValue) {
328
+ this._slottedDisabledOptions = [];
329
+ for (const option of oldValue) {
330
+ const notifier = vividElement.Observable.getNotifier(option);
331
+ notifier.unsubscribe(this.#slottedOptionsChangeHandler, "selected");
293
332
  }
294
- this.typeaheadExpired = false;
333
+ }
334
+ if (newValue) {
335
+ for (const option of newValue) {
336
+ option._displayCheckmark = true;
337
+ const notifier = vividElement.Observable.getNotifier(option);
338
+ notifier.subscribe(this.#slottedOptionsChangeHandler, "selected");
339
+ }
340
+ }
341
+ const values = [];
342
+ for (const option of this._slottedOptions) {
343
+ if (option.selected || option.value === this.value || this.values.includes(option.value)) {
344
+ values.push(option.value);
345
+ }
346
+ if (option.disabled) {
347
+ this._slottedDisabledOptions.push(option);
348
+ }
349
+ }
350
+ this.#updateValuesWhileMaintainingOrder(values);
351
+ this.#updateFilteredOptions();
352
+ this.#updateSelectionLimit();
353
+ }
354
+ #slottedOptionsChangeHandler;
355
+ #updateSelectedOnSlottedOptions() {
356
+ for (const option of this._slottedOptions) {
357
+ option.selected = this.values.includes(option.value);
358
+ this.#updateClonedTagIconOfOption(option);
359
+ }
360
+ }
361
+ #handleOptionInteraction(option) {
362
+ const value = option.value;
363
+ let newValues;
364
+ let shouldClearSearchText = false;
365
+ const isSelection = !this.values.includes(value);
366
+ if (this.multiple) {
367
+ if (isSelection) {
368
+ newValues = [...this.values, value];
369
+ } else {
370
+ newValues = this.values.filter((option2) => option2 !== value);
371
+ }
372
+ shouldClearSearchText = true;
373
+ } else {
374
+ if (isSelection) {
375
+ newValues = [value];
376
+ shouldClearSearchText = true;
377
+ } else {
378
+ newValues = [];
379
+ }
380
+ this.open = false;
381
+ }
382
+ this.#updateValuesThroughUserInteraction(newValues);
383
+ const optionMessage = isSelection ? this.locale.searchableSelect.optionSelectedMessage(option.text) : this.locale.searchableSelect.optionDeselectedMessage(option.text);
384
+ const maxSelectedMessage = this.multiple && this.maxSelected && this.maxSelected >= 1 ? this.locale.searchableSelect.maxSelectedMessage(
385
+ this.values.length,
386
+ this.maxSelected
387
+ ) : "";
388
+ this._changeDescription = `${optionMessage} ${maxSelectedMessage}`;
389
+ if (shouldClearSearchText) {
390
+ this._currentSearchText = null;
295
391
  }
296
392
  }
393
+ #clonedTagIcons;
394
+ #tagIconOfOption(option) {
395
+ return option.querySelector('[slot="tag-icon"]');
396
+ }
297
397
  /**
298
- * Unchecks all options.
299
- *
300
- * @remarks
301
- * Multiple-selection mode only.
302
- *
303
- * @param preserveChecked - reset the rangeStartIndex
304
- *
305
398
  * @internal
306
399
  */
307
- uncheckAllOptions(preserveChecked = false) {
308
- this.options.forEach((o) => o.checked = false);
309
- if (!preserveChecked) {
310
- this.rangeStartIndex = -1;
400
+ _tagIconSlotName(value) {
401
+ return `_tag-icon-${this.values.indexOf(value)}`;
402
+ }
403
+ #updateClonedTagIconOfOption(option) {
404
+ if (option.selected && this.#tagIconOfOption(option)) {
405
+ let clone = this.#clonedTagIcons.get(option);
406
+ if (!clone) {
407
+ clone = this.#tagIconOfOption(option).cloneNode(true);
408
+ this.#clonedTagIcons.set(option, clone);
409
+ }
410
+ clone.slot = this._tagIconSlotName(option.value);
411
+ this.appendChild(clone);
412
+ } else {
413
+ const clone = this.#clonedTagIcons.get(option);
414
+ if (clone) {
415
+ clone.remove();
416
+ this.#clonedTagIcons.delete(option);
417
+ }
311
418
  }
312
419
  }
313
420
  /**
314
- * Sets focus when the open property changes.
315
- *
316
421
  * @internal
317
422
  */
318
- openChanged(prev, next) {
319
- if (!this.collapsible) {
320
- return;
423
+ optionFilterChanged() {
424
+ this.#updateFilteredOptions();
425
+ }
426
+ #updateFilteredOptions() {
427
+ const newFilteredOptions = [];
428
+ const optionFilter = this.optionFilter ?? ((option, searchText) => option.text.toLowerCase().includes(searchText.toLowerCase()));
429
+ for (const option of this._slottedOptions ?? []) {
430
+ option._vvdSearchText = this.searchText;
431
+ const matches = !this.searchText || optionFilter(option, this.searchText);
432
+ option._isNotMatching = !matches;
433
+ if (!option.hidden && matches) {
434
+ newFilteredOptions.push(option);
435
+ }
321
436
  }
322
- if (this.open) {
323
- this.focusAndScrollOptionIntoView();
324
- this.indexWhenOpened = this.selectedIndex;
325
- vividElement.DOM.queueUpdate(() => this.focus());
326
- return;
437
+ this.#transitionHighlightedOptionTo(null);
438
+ this._filteredOptions = newFilteredOptions;
439
+ this._filteredEnabledOptions = newFilteredOptions.filter(
440
+ (option) => !option.disabled
441
+ );
442
+ }
443
+ #transitionHighlightedOptionTo(index) {
444
+ if (typeof this._highlightedOptionIndex === "number") {
445
+ this._filteredEnabledOptions[this._highlightedOptionIndex]._highlighted = false;
446
+ }
447
+ if (typeof index === "number") {
448
+ if (!this._filteredEnabledOptions.length) {
449
+ index = null;
450
+ } else {
451
+ index = Math.max(
452
+ 0,
453
+ Math.min(this._filteredEnabledOptions.length - 1, index)
454
+ );
455
+ }
456
+ }
457
+ this._highlightedOptionIndex = index;
458
+ if (typeof this._highlightedOptionIndex === "number") {
459
+ const highlightedOption = this._filteredEnabledOptions[this._highlightedOptionIndex];
460
+ highlightedOption._highlighted = true;
461
+ scrollIntoView.scrollIntoView(highlightedOption, this._listbox, "nearest");
462
+ this._changeDescription = this.locale.searchableSelect.optionFocusedMessage(
463
+ highlightedOption.text,
464
+ this._highlightedOptionIndex + 1,
465
+ this._filteredEnabledOptions.length
466
+ );
327
467
  }
328
- const didClose = prev === true && next === false;
329
- const selectionChangedWhileOpen = this.indexWhenOpened !== this.selectedIndex;
330
- if (didClose && selectionChangedWhileOpen) {
331
- this.updateValue(true);
468
+ }
469
+ #selectHighlightedOption() {
470
+ if (this._highlightedOptionIndex === null) {
471
+ return;
332
472
  }
473
+ this.#handleOptionInteraction(
474
+ this._filteredEnabledOptions[this._highlightedOptionIndex]
475
+ );
333
476
  }
334
- get collapsible() {
335
- return !this.multiple;
477
+ #highlightFirstOption() {
478
+ this.#transitionHighlightedOptionTo(0);
336
479
  }
480
+ #highlightLastOption() {
481
+ this.#transitionHighlightedOptionTo(
482
+ this._filteredEnabledOptions.length - 1
483
+ );
484
+ }
485
+ #highlightPrevPage() {
486
+ this.#transitionHighlightedOptionTo(
487
+ (this._highlightedOptionIndex ?? this._filteredEnabledOptions.length) - PageSize
488
+ );
489
+ }
490
+ #highlightNextPage() {
491
+ this.#transitionHighlightedOptionTo(
492
+ (this._highlightedOptionIndex ?? -1) + PageSize
493
+ );
494
+ }
495
+ #highlightPreviousOption() {
496
+ this.#transitionHighlightedOptionTo(
497
+ (this._highlightedOptionIndex ?? this._filteredEnabledOptions.length) - 1
498
+ );
499
+ }
500
+ #highlightNextOption() {
501
+ this.#transitionHighlightedOptionTo(
502
+ (this._highlightedOptionIndex ?? -1) + 1
503
+ );
504
+ }
505
+ // --- Tags ---
337
506
  /**
338
- * The value property.
339
- *
340
- * @public
507
+ * @internal
341
508
  */
342
- get value() {
343
- vividElement.Observable.track(this, "value");
344
- return this._value;
345
- }
346
- set value(next) {
347
- const prev = `${this._value}`;
348
- if (this.length) {
349
- const selectedIndex = this._options.findIndex((el) => el.value === next);
350
- const prevSelectedValue = this._options[this.selectedIndex]?.value ?? null;
351
- const nextSelectedValue = this._options[selectedIndex]?.value ?? null;
352
- if (selectedIndex === -1 || prevSelectedValue !== nextSelectedValue) {
353
- next = "";
354
- this.selectedIndex = selectedIndex;
355
- }
356
- next = this.firstSelectedOption?.value ?? next;
357
- }
358
- if (prev !== next) {
359
- this._value = next;
360
- super.valueChanged(prev, next);
361
- vividElement.Observable.notify(this, "value");
362
- this.updateDisplayValue();
363
- }
509
+ _tagLabelForValue(value) {
510
+ const option = this._slottedOptions.find(
511
+ (option2) => option2.value === value
512
+ );
513
+ return option.label;
364
514
  }
365
515
  /**
366
- * Sets the value and display value to match the first selected option.
367
- *
368
- * @param shouldEmit - if true, the input and change events will be emitted
369
- *
370
516
  * @internal
371
517
  */
372
- updateValue(shouldEmit) {
373
- if (this.$fastController.isConnected) {
374
- this.value = this.firstSelectedOption?.value ?? "";
375
- }
376
- if (shouldEmit) {
377
- this.$emit("input");
378
- this.$emit("change", this, {
379
- bubbles: true,
380
- composed: void 0
381
- });
382
- }
518
+ _tagConnotationForValue(value) {
519
+ const option = this._slottedOptions.find(
520
+ (option2) => option2.value === value
521
+ );
522
+ return option.tagConnotation;
383
523
  }
384
524
  /**
385
- * Updates the proxy value when the selected index changes.
386
- *
387
- * @param prev - the previous selected index
388
- * @param next - the next selected index
389
- *
390
525
  * @internal
391
526
  */
392
- selectedIndexChanged(prev, next) {
393
- super.selectedIndexChanged(prev, next);
394
- this.updateValue();
527
+ _isTagDisabled(value) {
528
+ const option = this._slottedOptions.find(
529
+ (option2) => option2.value === value
530
+ );
531
+ return this.disabled || option.disabled;
532
+ }
533
+ #textForValue(value) {
534
+ return this._slottedOptions?.find((option) => option.value === value)?.text;
395
535
  }
396
536
  /**
397
- * Handle opening and closing the listbox when the select is clicked.
398
- *
399
- * @param e - the mouse event
400
537
  * @internal
401
538
  */
402
- clickHandler(e) {
403
- if (this.disabled) {
539
+ #measureTagWidth(label, removable, hasIcon) {
540
+ const tag = document.createElement(this._optionTagTagName);
541
+ tag.label = label;
542
+ tag.removable = removable;
543
+ tag.style.cssText = "position: absolute; visibility: hidden;";
544
+ tag.hasIconPlaceholder = hasIcon;
545
+ this.shadowRoot.appendChild(tag);
546
+ const width = tag.getBoundingClientRect().width;
547
+ tag.remove();
548
+ return width;
549
+ }
550
+ #updateTagLayout() {
551
+ if (!this.multiple) {
552
+ this._numElidedTags = 0;
553
+ this._tagRows = [];
554
+ this._lastTagRow = [];
404
555
  return;
405
556
  }
406
- const clickedOption = e.target.closest(
407
- `option,[role=option]`
408
- );
409
- if (clickedOption && clickedOption.disabled) {
557
+ if (this.externalTags) {
558
+ this._numElidedTags = this.values.length;
559
+ this._tagRows = [];
560
+ this._lastTagRow = [];
410
561
  return;
411
562
  }
412
- if (this.multiple) {
413
- this.uncheckAllOptions();
414
- this.activeIndex = this.options.indexOf(clickedOption);
415
- this.checkActiveIndex();
416
- this.toggleSelectedForAllCheckedOptions();
417
- } else {
418
- super.clickHandler(e);
563
+ const rowWidth = this._contentArea.getBoundingClientRect().width;
564
+ const rows = [[]];
565
+ let currentRowIndex = 0;
566
+ let currentRowWidth = InputMinWidthPx;
567
+ let i;
568
+ for (i = this.values.length - 1; i >= 0; i--) {
569
+ const isLastRow = this.maxLines && currentRowIndex === this.maxLines - 1;
570
+ const tagWidth = this.#measureTagWidth(
571
+ this._tagLabelForValue(this.values[i]),
572
+ true,
573
+ this.#tagIconOfOption(this.selectedOptions[i]) !== null
574
+ );
575
+ const entry = {
576
+ value: this.values[i],
577
+ width: tagWidth
578
+ };
579
+ let elidedTagCounterWidth = 0;
580
+ if (isLastRow) {
581
+ const numElidedTags = i;
582
+ if (numElidedTags) {
583
+ elidedTagCounterWidth = TagGapPx + this.#measureTagWidth(numElidedTags.toString(), false, false);
584
+ }
585
+ }
586
+ const totalWidthNeeded = currentRowWidth + TagGapPx + tagWidth + elidedTagCounterWidth;
587
+ if (totalWidthNeeded > rowWidth) {
588
+ if (isLastRow) {
589
+ if (i === this.values.length - 1) {
590
+ rows[currentRowIndex].unshift(entry);
591
+ currentRowWidth += TagGapPx + tagWidth;
592
+ } else {
593
+ break;
594
+ }
595
+ } else {
596
+ rows.push([]);
597
+ currentRowIndex++;
598
+ rows[currentRowIndex].unshift(entry);
599
+ currentRowWidth = tagWidth;
600
+ }
601
+ continue;
602
+ }
603
+ rows[currentRowIndex].unshift(entry);
604
+ currentRowWidth += TagGapPx + tagWidth;
419
605
  }
420
- if (this.collapsible) {
421
- this.open = !this.open;
606
+ this._numElidedTags = i + 1;
607
+ rows.reverse();
608
+ for (let i2 = 0; i2 < rows.length - 1; i2++) {
609
+ let lineWidth = rows[i2].map((e) => e.width).reduce((a, b) => a + b, 0) + (rows[i2].length - 1) * TagGapPx;
610
+ if (i2 === 0 && this._numElidedTags) {
611
+ lineWidth += TagGapPx + this.#measureTagWidth(this._numElidedTags.toString(), false, false);
612
+ }
613
+ while (rows[i2 + 1].length && lineWidth + TagGapPx + rows[i2 + 1][0].width <= rowWidth) {
614
+ const nextTag = rows[i2 + 1].shift();
615
+ rows[i2].push(nextTag);
616
+ lineWidth += TagGapPx + nextTag.width;
617
+ }
422
618
  }
423
- return true;
619
+ const rowValues = rows.map((line) => line.map((entry) => entry.value));
620
+ this._tagRows = rowValues.slice(0, -1);
621
+ this._lastTagRow = rowValues.slice(-1)[0];
424
622
  }
425
623
  /**
426
- * Handles focus state when the element or its children lose focus.
427
- *
428
- * @param e - The focus event
429
624
  * @internal
430
625
  */
431
- focusoutHandler(e) {
432
- if (this.multiple) {
433
- this.uncheckAllOptions();
626
+ _onTagRemoved(value) {
627
+ this.#updateValuesThroughUserInteraction(
628
+ this.values.filter((option) => option !== value)
629
+ );
630
+ this.#updateFilteredOptions();
631
+ }
632
+ /**
633
+ * @internal
634
+ */
635
+ _onTagKeydown(event) {
636
+ const tagIndex = parseInt(event.target.dataset.index);
637
+ switch (event.key) {
638
+ case "Backspace":
639
+ case "Delete":
640
+ case "Enter":
641
+ case " ": {
642
+ this._onTagRemoved(this.values[tagIndex]);
643
+ vividElement.DOM.processUpdates();
644
+ this.#moveTagFocusTo(this.#nextTagIndexForRemoved(tagIndex));
645
+ break;
646
+ }
647
+ case "ArrowLeft":
648
+ this.#moveTagFocusTo(this.#nextTagIndexLeft(tagIndex) ?? tagIndex);
649
+ break;
650
+ case "ArrowRight":
651
+ this.#moveTagFocusTo(this.#nextTagIndexRight(tagIndex));
652
+ break;
434
653
  }
435
- if (!this.open) {
436
- return true;
654
+ return true;
655
+ }
656
+ #moveTagFocusTo(index) {
657
+ if (index === null) {
658
+ this._input.focus();
659
+ } else {
660
+ this.shadowRoot.querySelector(`[data-index="${index}"]`)?.focus();
437
661
  }
438
- const focusTarget = e.relatedTarget;
439
- if (this.isSameNode(focusTarget)) {
440
- this.focus();
441
- return;
662
+ }
663
+ #nextTagIndexLeft(index) {
664
+ if (!this.values.length) {
665
+ return null;
442
666
  }
443
- if (!this.options.includes(focusTarget)) {
444
- this.open = false;
445
- if (this.indexWhenOpened !== this.selectedIndex) {
446
- this.updateValue(true);
667
+ for (let i = index - 1; i >= 0; i--) {
668
+ if (!this._isTagDisabled(this.values[i])) {
669
+ return i;
447
670
  }
448
671
  }
672
+ return null;
673
+ }
674
+ #nextTagIndexRight(index) {
675
+ if (!this.values.length) {
676
+ return null;
677
+ }
678
+ for (let i = index + 1; i < this.values.length; i++) {
679
+ if (!this._isTagDisabled(this.values[i])) {
680
+ return i;
681
+ }
682
+ }
683
+ return null;
684
+ }
685
+ #nextTagIndexForRemoved(index) {
686
+ return this.#nextTagIndexRight(index - 1) ?? this.#nextTagIndexLeft(index);
449
687
  }
450
688
  /**
451
- * Updates the value when an option's value changes.
452
- *
453
- * @param source - the source object
454
- * @param propertyName - the property to evaluate
455
- *
456
689
  * @internal
457
690
  */
458
- handleChange(source, propertyName) {
459
- super.handleChange(source, propertyName);
460
- if (propertyName === "value") {
461
- this.updateValue();
691
+ _onListboxClick(e) {
692
+ if (this.disabled) {
693
+ return;
694
+ }
695
+ const capturedOption = e.target.closest(
696
+ `option,[role=option]`
697
+ );
698
+ if (capturedOption && !capturedOption.disabled) {
699
+ this.#handleOptionInteraction(capturedOption);
462
700
  }
463
701
  }
464
702
  /**
465
- * Prevents focus when a scrollbar is clicked.
466
- *
467
- * @param e - the mouse event object
468
- *
469
703
  * @internal
470
704
  */
471
- mousedownHandler(e) {
472
- if (e.offsetX >= 0 && e.offsetX <= this.listbox.scrollWidth) {
473
- return super.mousedownHandler(e);
474
- }
475
- return this.collapsible;
705
+ get _shouldShowClearButton() {
706
+ return this.clearable && this.values.length > 0;
476
707
  }
477
708
  /**
478
709
  * @internal
479
710
  */
480
- multipleChanged(_, next) {
481
- this.options.forEach((o) => {
482
- o.checked = next ? false : void 0;
483
- });
484
- this.setSelectedOptions();
485
- if (this.proxy) {
486
- this.proxy.multiple = next;
487
- }
711
+ _onClearButtonClick() {
712
+ this.#updateValuesThroughUserInteraction(
713
+ this.selectedOptions.filter((option) => option.disabled).map((option) => option.value)
714
+ );
488
715
  }
489
716
  /**
490
- * Updates the selectedness of each option when the list of selected options changes.
491
- *
492
- * @param prev - the previous list of selected options
493
- * @param next - the current list of selected options
494
- *
495
717
  * @internal
496
718
  */
497
- selectedOptionsChanged(prev, next) {
498
- super.selectedOptionsChanged(prev, next);
499
- this.options.forEach((o, i) => {
500
- const proxyOption = this.proxy.options.item(i);
501
- if (proxyOption) {
502
- proxyOption.selected = o.selected;
719
+ maxSelectedChanged() {
720
+ this.#updateSelectionLimit();
721
+ }
722
+ #updateSelectionLimit() {
723
+ if (!this.multiple || typeof this.maxSelected !== "number" || this.maxSelected <= 0) {
724
+ return;
725
+ }
726
+ const options = this._slottedOptions.filter(
727
+ (option) => !this._slottedDisabledOptions.includes(option)
728
+ );
729
+ if (this.values.length >= this.maxSelected) {
730
+ const unselectedOptions = options.filter(
731
+ (option) => !this.selectedOptions.includes(option)
732
+ );
733
+ for (const option of unselectedOptions) {
734
+ option.disabled = true;
503
735
  }
504
- });
736
+ } else {
737
+ for (const option of options) {
738
+ option.disabled = false;
739
+ }
740
+ }
741
+ }
742
+ #determineInitialValues() {
743
+ return this.initialValues.length ? this.initialValues : this.initialValue ? [this.initialValue] : [];
505
744
  }
506
745
  /**
507
- * Resets and fills the proxy to match the component's options.
508
- *
509
746
  * @internal
510
747
  */
511
- setProxyOptions() {
512
- if (this.proxy instanceof HTMLSelectElement && this.options) {
513
- this.proxy.length = 0;
514
- this.options.forEach((option) => {
515
- const proxyOption = option.proxy || (option instanceof HTMLOptionElement ? option.cloneNode() : null);
516
- if (proxyOption) {
517
- this.proxy.options.add(proxyOption);
518
- }
519
- });
748
+ nameChanged(previous, next) {
749
+ super.nameChanged(previous, next);
750
+ this.#updateFormValue();
751
+ }
752
+ #updateFormValue() {
753
+ if (!this.name) {
754
+ this.setFormValue(null);
755
+ } else {
756
+ const formData = new FormData();
757
+ for (const value of this.values) {
758
+ formData.append(this.name, value);
759
+ }
760
+ this.setFormValue(formData);
520
761
  }
521
762
  }
522
763
  /**
523
- * Handles keydown actions when the select is in multiple selection mode.
524
- *
525
764
  * @internal
526
765
  */
527
- multipleKeydownHandler(e) {
766
+ formResetCallback() {
767
+ super.formResetCallback();
768
+ this.#updateValuesThroughUserInteraction(this.#determineInitialValues());
769
+ }
770
+ #resizeObserver;
771
+ /**
772
+ * @internal
773
+ */
774
+ _onFieldsetClick(e) {
528
775
  if (this.disabled) {
529
776
  return;
530
777
  }
531
- const { key, shiftKey } = e;
532
- this.shouldSkipFocus = false;
533
- switch (key) {
534
- case keyCodes.keyHome: {
535
- this.checkFirstOption(shiftKey);
536
- return;
537
- }
538
- case keyCodes.keyArrowDown: {
539
- this.checkNextOption(shiftKey);
540
- return;
541
- }
542
- case keyCodes.keyArrowUp: {
543
- this.checkPreviousOption(shiftKey);
544
- return;
545
- }
546
- case keyCodes.keyEnd: {
547
- this.checkLastOption(shiftKey);
548
- return;
549
- }
550
- case keyCodes.keyTab: {
551
- this.focusAndScrollOptionIntoView();
552
- return;
553
- }
554
- case keyCodes.keyEscape: {
555
- this.uncheckAllOptions();
556
- this.checkActiveIndex();
557
- return;
558
- }
559
- case keyCodes.keySpace: {
560
- e.preventDefault();
561
- if (this.typeaheadExpired) {
562
- this.toggleSelectedForAllCheckedOptions();
563
- return;
564
- }
565
- }
566
- default: {
567
- if (key.length === 1) {
568
- this.handleTypeAhead(`${key}`);
569
- }
570
- return;
571
- }
778
+ if (!e.defaultPrevented) {
779
+ this._input.focus();
780
+ this.open = true;
572
781
  }
573
782
  }
574
783
  /**
575
- * Handle keyboard interaction for the select.
576
- *
577
- * @param e - the keyboard event
578
784
  * @internal
579
785
  */
580
- keydownHandler(e) {
581
- const selectedIndexBefore = this.selectedIndex;
582
- if (this.multiple) {
583
- this.multipleKeydownHandler(e);
584
- } else {
585
- super.keydownHandler(e);
586
- }
587
- const key = e.key;
588
- switch (key) {
589
- case keyCodes.keySpace: {
590
- e.preventDefault();
591
- if (this.collapsible && this.typeaheadExpired) {
592
- this.open = !this.open;
593
- }
594
- break;
595
- }
596
- case keyCodes.keyHome:
597
- case keyCodes.keyEnd: {
598
- e.preventDefault();
599
- break;
600
- }
601
- case keyCodes.keyEnter: {
602
- e.preventDefault();
603
- this.open = !this.open;
604
- break;
605
- }
606
- case keyCodes.keyEscape: {
607
- if (this.collapsible && this.open) {
608
- e.preventDefault();
609
- this.open = false;
610
- }
611
- break;
612
- }
613
- case keyCodes.keyTab: {
614
- if (this.collapsible && this.open) {
615
- e.preventDefault();
616
- this.open = false;
617
- }
618
- return true;
619
- }
620
- }
621
- if (this.collapsible && !this.open && this.selectedIndex !== selectedIndexBefore) {
622
- this.updateValue(true);
786
+ _onChevronClick() {
787
+ if (this.open) {
788
+ this.open = false;
789
+ return false;
623
790
  }
624
- return !(e.key === keyCodes.keyArrowDown || e.key === keyCodes.keyArrowUp);
791
+ return true;
625
792
  }
626
793
  connectedCallback() {
627
794
  super.connectedCallback();
628
- this.addEventListener("focusout", this.focusoutHandler);
629
- this.addEventListener("contentchange", this.updateDisplayValue);
795
+ if (!this.values.length) {
796
+ this.values = this.#determineInitialValues();
797
+ }
798
+ this.#resizeObserver.observe(this._contentArea);
630
799
  }
631
800
  disconnectedCallback() {
632
- this.removeEventListener("focusout", this.focusoutHandler);
633
- this.removeEventListener("contentchange", this.updateDisplayValue);
634
801
  super.disconnectedCallback();
802
+ this.#resizeObserver.disconnect();
635
803
  }
636
804
  /**
637
- *
638
805
  * @internal
639
806
  */
640
- updateDisplayValue() {
641
- if (this.collapsible) {
642
- vividElement.Observable.notify(this, "displayValue");
643
- }
644
- }
645
- labelChanged() {
646
- if (!this.ariaLabel) {
647
- this.ariaLabel = this.label;
648
- }
649
- }
650
- get displayValue() {
651
- vividElement.Observable.track(this, "displayValue");
652
- return this.firstSelectedOption?.getAttribute("label") ?? this.firstSelectedOption?.text ?? this.placeholder ?? "";
653
- }
654
- setDefaultSelectedOption() {
655
- const options = Array.from(this.children).filter(
656
- listbox.Listbox.slottedOptionFilter
657
- );
658
- const selectedIndex = options.findIndex(
659
- (el) => el.hasAttribute("selected") || el.selected || el.value === this.value
660
- );
661
- if (selectedIndex === -1 && !this.placeholderOption) {
662
- this.selectedIndex = 0;
663
- return;
664
- }
665
- if (selectedIndex !== -1 || this.placeholder !== "") {
666
- this.selectedIndex = selectedIndex;
667
- return;
668
- }
807
+ validate() {
808
+ super.validate(this._input ?? void 0);
669
809
  }
670
- /*
810
+ /**
671
811
  * @internal
672
812
  */
673
- slottedOptionsChanged(prev, next) {
674
- this.options.forEach((o) => {
675
- const notifier = vividElement.Observable.getNotifier(o);
676
- notifier.unsubscribe(this, "value");
677
- });
678
- super.slottedOptionsChanged(prev, next);
679
- this.options.forEach((o) => {
680
- const notifier = vividElement.Observable.getNotifier(o);
681
- notifier.subscribe(this, "value");
682
- });
683
- this.setProxyOptions();
684
- this.updateValue();
685
- const scale = this.getAttribute("scale") || this.scale;
686
- next.forEach((element) => {
687
- if (scale) {
688
- element.setAttribute("scale", scale);
689
- element.scale = scale;
690
- }
691
- });
692
- this.proxy.value = this.value;
693
- this.validate();
813
+ focus(options) {
814
+ this._input?.focus(options);
694
815
  }
695
- formResetCallback() {
696
- this.setProxyOptions();
697
- super.setDefaultSelectedOption();
698
- if (this.selectedIndex === -1) {
699
- this.selectedIndex = 0;
700
- }
701
- if (this.placeholder) {
702
- this.selectedIndex = -1;
816
+ /**
817
+ * @internal
818
+ */
819
+ _onMouseDown(event) {
820
+ const originalTarget = event.composedPath()[0];
821
+ if (!event.defaultPrevented && originalTarget !== this._input) {
822
+ this._input.focus();
823
+ return false;
703
824
  }
825
+ return true;
704
826
  }
705
- };
706
- __decorateClass([
827
+ }
828
+ __decorateClass$1([
829
+ vividElement.attr
830
+ ], SearchableSelect.prototype, "appearance");
831
+ __decorateClass$1([
832
+ vividElement.attr
833
+ ], SearchableSelect.prototype, "shape");
834
+ __decorateClass$1([
835
+ vividElement.attr({ mode: "boolean", attribute: "fixed-dropdown" })
836
+ ], SearchableSelect.prototype, "fixedDropdown");
837
+ __decorateClass$1([
838
+ vividElement.attr
839
+ ], SearchableSelect.prototype, "placeholder");
840
+ __decorateClass$1([
841
+ vividElement.attr({ mode: "boolean" })
842
+ ], SearchableSelect.prototype, "open");
843
+ __decorateClass$1([
844
+ vividElement.attr({ mode: "boolean" })
845
+ ], SearchableSelect.prototype, "multiple");
846
+ __decorateClass$1([
847
+ vividElement.attr({ attribute: "external-tags", mode: "boolean" })
848
+ ], SearchableSelect.prototype, "externalTags");
849
+ __decorateClass$1([
850
+ vividElement.attr({ attribute: "max-lines", converter: vividElement.nullableNumberConverter })
851
+ ], SearchableSelect.prototype, "maxLines");
852
+ __decorateClass$1([
707
853
  vividElement.observable
708
- ], exports.Select.prototype, "activeIndex", 2);
709
- // @ts-expect-error Type is incorrectly non-optional
710
- __decorateClass([
854
+ ], SearchableSelect.prototype, "values");
855
+ __decorateClass$1([
856
+ vividElement.observable
857
+ ], SearchableSelect.prototype, "initialValues");
858
+ __decorateClass$1([
859
+ vividElement.observable
860
+ ], SearchableSelect.prototype, "_input");
861
+ __decorateClass$1([
862
+ vividElement.observable
863
+ ], SearchableSelect.prototype, "_currentSearchText");
864
+ __decorateClass$1([
865
+ vividElement.observable
866
+ ], SearchableSelect.prototype, "_slottedOptions");
867
+ __decorateClass$1([
868
+ vividElement.observable
869
+ ], SearchableSelect.prototype, "optionFilter");
870
+ __decorateClass$1([
871
+ vividElement.observable
872
+ ], SearchableSelect.prototype, "_filteredOptions");
873
+ __decorateClass$1([
874
+ vividElement.observable
875
+ ], SearchableSelect.prototype, "_filteredEnabledOptions");
876
+ __decorateClass$1([
877
+ vividElement.attr({
878
+ mode: "boolean"
879
+ })
880
+ ], SearchableSelect.prototype, "loading");
881
+ __decorateClass$1([
882
+ vividElement.observable
883
+ ], SearchableSelect.prototype, "_highlightedOptionIndex");
884
+ __decorateClass$1([
885
+ vividElement.observable
886
+ ], SearchableSelect.prototype, "_contentArea");
887
+ __decorateClass$1([
888
+ vividElement.observable
889
+ ], SearchableSelect.prototype, "_numElidedTags");
890
+ __decorateClass$1([
891
+ vividElement.observable
892
+ ], SearchableSelect.prototype, "_tagRows");
893
+ __decorateClass$1([
894
+ vividElement.observable
895
+ ], SearchableSelect.prototype, "_lastTagRow");
896
+ __decorateClass$1([
897
+ vividElement.observable
898
+ ], SearchableSelect.prototype, "_listbox");
899
+ __decorateClass$1([
711
900
  vividElement.attr({ mode: "boolean" })
712
- ], exports.Select.prototype, "multiple", 2);
713
- __decorateClass([
714
- vividElement.attr({ attribute: "open", mode: "boolean" })
715
- ], exports.Select.prototype, "open", 2);
716
- __decorateClass([
717
- vividElement.volatile
718
- ], exports.Select.prototype, "collapsible", 1);
719
- __decorateClass([
901
+ ], SearchableSelect.prototype, "clearable");
902
+ __decorateClass$1([
903
+ vividElement.attr({ attribute: "max-selected", converter: vividElement.nullableNumberConverter })
904
+ ], SearchableSelect.prototype, "maxSelected");
905
+ __decorateClass$1([
720
906
  vividElement.observable
721
- ], exports.Select.prototype, "control", 2);
722
- __decorateClass([
907
+ ], SearchableSelect.prototype, "_slottedDisabledOptions");
908
+ __decorateClass$1([
723
909
  vividElement.observable
724
- ], exports.Select.prototype, "maxHeight", 2);
725
- __decorateClass([
910
+ ], SearchableSelect.prototype, "_changeDescription");
911
+ __decorateClass$1([
726
912
  vividElement.observable
727
- ], exports.Select.prototype, "_anchor", 2);
728
- __decorateClass([
729
- vividElement.attr()
730
- ], exports.Select.prototype, "scale", 2);
731
- __decorateClass([
732
- vividElement.attr
733
- ], exports.Select.prototype, "appearance", 2);
913
+ ], SearchableSelect.prototype, "_anchor");
914
+
915
+ var __defProp = Object.defineProperty;
916
+ var __decorateClass = (decorators, target, key, kind) => {
917
+ var result = void 0 ;
918
+ for (var i = decorators.length - 1, decorator; i >= 0; i--)
919
+ if (decorator = decorators[i])
920
+ result = (decorator(target, key, result) ) || result;
921
+ if (result) __defProp(target, key, result);
922
+ return result;
923
+ };
924
+ class OptionTag extends localized.Localized(vividElement.VividElement) {
925
+ constructor() {
926
+ super(...arguments);
927
+ this.removable = false;
928
+ this.disabled = false;
929
+ this.hasIconPlaceholder = false;
930
+ }
931
+ _onClickRemove() {
932
+ this.$emit("remove", void 0, {
933
+ bubbles: false
934
+ });
935
+ }
936
+ }
734
937
  __decorateClass([
735
938
  vividElement.attr
736
- ], exports.Select.prototype, "shape", 2);
939
+ ], OptionTag.prototype, "shape");
737
940
  __decorateClass([
738
- vividElement.attr({ mode: "boolean", attribute: "fixed-dropdown" })
739
- ], exports.Select.prototype, "fixedDropdown", 2);
941
+ vividElement.observable
942
+ ], OptionTag.prototype, "connotation");
740
943
  __decorateClass([
741
944
  vividElement.attr
742
- ], exports.Select.prototype, "placeholder", 2);
945
+ ], OptionTag.prototype, "label");
743
946
  __decorateClass([
744
- vividElement.observable
745
- ], exports.Select.prototype, "placeholderOption", 2);
947
+ vividElement.attr({ mode: "boolean" })
948
+ ], OptionTag.prototype, "removable");
746
949
  __decorateClass([
747
- vividElement.observable
748
- ], exports.Select.prototype, "_feedbackWrapper", 2);
950
+ vividElement.attr({ mode: "boolean" })
951
+ ], OptionTag.prototype, "disabled");
749
952
  __decorateClass([
750
953
  vividElement.observable
751
- ], exports.Select.prototype, "metaSlottedContent", 2);
752
- exports.Select = __decorateClass([
753
- formElements.errorText,
754
- formElements.formElements
755
- ], exports.Select);
756
- applyMixinsWithObservables.applyMixinsWithObservables(
757
- exports.Select,
758
- formElements.FormElementHelperText,
759
- formElements.FormElementSuccessText
760
- );
954
+ ], OptionTag.prototype, "hasIconPlaceholder");
761
955
 
762
- const getStateClasses = ({
763
- shape,
764
- disabled,
765
- appearance,
766
- metaSlottedContent,
767
- errorValidationMessage,
768
- successText,
769
- placeholder,
770
- value,
771
- scale
772
- }) => classNames.classNames(
773
- ["disabled", disabled],
774
- [`appearance-${appearance}`, Boolean(appearance)],
775
- [`shape-${shape}`, Boolean(shape)],
776
- ["has-meta", Boolean(metaSlottedContent?.length)],
777
- ["error", Boolean(errorValidationMessage)],
778
- ["success", !!successText],
779
- ["shows-placeholder", Boolean(placeholder) && !value],
780
- [`size-${scale}`, Boolean(scale)]
956
+ const getStateClasses = (x) => classNames.classNames(
957
+ ["disabled", x.disabled],
958
+ [`appearance-${x.appearance}`, Boolean(x.appearance)],
959
+ [`shape-${x.shape}`, Boolean(x.shape)],
960
+ ["error", Boolean(x.errorValidationMessage)],
961
+ ["success", !!x.successText]
781
962
  );
782
963
  function renderLabel() {
783
- return vividElement.html` <label
784
- for="${(x) => x.multiple ? null : "control"}"
785
- class="label"
786
- id="label"
787
- >
788
- ${(x) => x.label}
789
- </label>`;
964
+ return vividElement.html`
965
+ <label for="control" class="label" id="label"> ${(x) => x.label} </label>
966
+ `;
790
967
  }
791
- function renderPlaceholder(context) {
792
- const optionTag = context.tagFor(option.ListboxOption);
968
+ function renderSelectionCount() {
793
969
  return vividElement.html`
794
- <${optionTag} ${ref.ref("placeholderOption")}
795
- text="${(x) => x.placeholder}" hidden disabled>
796
- </${optionTag}>`;
970
+ <span
971
+ id="selection-count"
972
+ class="selection-count"
973
+ aria-label="${(x) => x.locale.searchableSelect.maxSelectedMessage(
974
+ x.values.length,
975
+ x.maxSelected
976
+ )}"
977
+ >(${(x) => `${x.values.length}/${x.maxSelected}`})</span
978
+ >
979
+ `;
797
980
  }
798
- function selectValue(context) {
981
+ const tagTemplateFactory = (context, getComponent) => {
982
+ const optionTagTag = context.tagFor(OptionTag);
983
+ return vividElement.html`
984
+ <div class="tag-wrapper">
985
+ <${optionTagTag}
986
+ class="tag"
987
+ tabindex="-1"
988
+ data-index="${(x, c) => getComponent(c).values.indexOf(x)}"
989
+ removable
990
+ :label="${(x, c) => getComponent(c)._tagLabelForValue(x)}"
991
+ :shape="${(_, c) => getComponent(c).shape}"
992
+ :connotation="${(x, c) => getComponent(c)._tagConnotationForValue(x)}"
993
+ ?disabled="${(x, c) => getComponent(c)._isTagDisabled(x)}"
994
+ @remove="${(x, c) => getComponent(c)._onTagRemoved(x)}"
995
+ @keydown="${(_, c) => getComponent(c)._onTagKeydown(c.event)}"
996
+ @mousedown="${() => false}">
997
+ <slot slot="icon" name="${(x, c) => getComponent(c)._tagIconSlotName(x)}"></slot>
998
+ </${optionTagTag}>
999
+ </div>
1000
+ `;
1001
+ };
1002
+ const elidedTagTemplateFactory = (context, getComponent) => {
1003
+ const optionTagTag = context.tagFor(OptionTag);
1004
+ return vividElement.html`
1005
+ <${optionTagTag}
1006
+ class="tag"
1007
+ tabindex="-1"
1008
+ :label="${(x, c) => getComponent(x, c)._numElidedTags.toString()}"
1009
+ :shape="${(x, c) => getComponent(x, c).shape}"
1010
+ ?disabled="${(x, c) => getComponent(x, c).disabled}"
1011
+ @mousedown="${() => false}">
1012
+ </${optionTagTag}>
1013
+ `;
1014
+ };
1015
+ function renderFieldset(context) {
1016
+ const buttonTag = context.tagFor(definition$1.Button);
1017
+ const progressRingTag = context.tagFor(definition$2.ProgressRing);
799
1018
  const affixIconTemplate = affix.affixIconTemplateFactory(context);
800
1019
  const chevronTemplate = definition$1.chevronTemplateFactory(context);
801
- return vividElement.html` <div
802
- class="control ${getStateClasses}"
803
- ${ref.ref("_anchor")}
804
- id="control"
805
- ?disabled="${(x) => x.disabled}"
806
- >
807
- <div class="selected-value">
1020
+ const tagTemplate = tagTemplateFactory(context, (c) => c.parent);
1021
+ const nestedTagTemplate = tagTemplateFactory(
1022
+ context,
1023
+ (c) => c.parentContext.parent
1024
+ );
1025
+ const elidedTagTemplate = elidedTagTemplateFactory(context, (x, _) => x);
1026
+ const nestedElidedTagTemplate = elidedTagTemplateFactory(
1027
+ context,
1028
+ (_, c) => c.parent
1029
+ );
1030
+ return vividElement.html`
1031
+ <div
1032
+ class="fieldset ${getStateClasses}"
1033
+ @click="${(x, c) => x._onFieldsetClick(c.event)}"
1034
+ ${ref.ref("_anchor")}
1035
+ >
808
1036
  ${(x) => affixIconTemplate(x.icon, affix.IconWrapper.Slot)}
809
- <span class="text">${(x) => x.displayValue}</span>
810
- <slot name="meta" ${slotted.slotted("metaSlottedContent")}></slot>
1037
+ <div class="content-area" ${ref.ref("_contentArea")}>
1038
+ ${repeat.repeat(
1039
+ (x) => x._tagRows,
1040
+ vividElement.html`
1041
+ <div class="tag-row">
1042
+ ${when.when(
1043
+ (_, c) => c.isFirst && c.parent._numElidedTags,
1044
+ nestedElidedTagTemplate
1045
+ )}
1046
+ ${repeat.repeat((x) => x, nestedTagTemplate)}
1047
+ </div>
1048
+ `,
1049
+ { positioning: true }
1050
+ )}
1051
+ <div
1052
+ class="tag-row ${(x) => classNames.classNames([
1053
+ "contains-only-input",
1054
+ x._tagRows.length > 0 && x._lastTagRow.length === 0
1055
+ ])}"
1056
+ >
1057
+ ${when.when(
1058
+ (x) => x._tagRows.length === 0 && x._numElidedTags,
1059
+ elidedTagTemplate
1060
+ )}
1061
+ ${repeat.repeat((x) => x._lastTagRow, tagTemplate)}
1062
+ <input
1063
+ id="control"
1064
+ class="control"
1065
+ autocomplete="off"
1066
+ aria-controls="listbox"
1067
+ aria-describedby="${(x) => x._feedbackDescribedBy} ${(x) => x.multiple && x.maxSelected && x.maxSelected >= 1 ? "selection-count" : null}"
1068
+ ${delegatesAria.delegateAria({
1069
+ role: "combobox",
1070
+ ariaAutoComplete: "list",
1071
+ ariaHasPopup: "listbox",
1072
+ ariaExpanded: (x) => x.open
1073
+ })}
1074
+ placeholder="${(x) => x.multiple && x.values.length ? "" : x.placeholder}"
1075
+ type="text"
1076
+ ?disabled="${(x) => x.disabled}"
1077
+ :value="${(x) => x._inputValue}"
1078
+ @input="${(x, c) => {
1079
+ x._onInputInput(c.event);
1080
+ c.event.stopPropagation();
1081
+ }}"
1082
+ @change="${(_, c) => {
1083
+ c.event.stopPropagation();
1084
+ }}"
1085
+ @focus="${(x, c) => x._onInputFocus(c.event)}"
1086
+ @blur="${(x, c) => x._onInputBlur(c.event)}"
1087
+ @keydown="${(x, c) => x._onInputKeydown(c.event)}"
1088
+ ${ref.ref("_input")}
1089
+ />
1090
+ </div>
1091
+ </div>
1092
+ <slot name="meta"></slot>
1093
+ ${when.when(
1094
+ (x) => x._shouldShowClearButton,
1095
+ vividElement.html`<${buttonTag}
1096
+ aria-label="${(x) => x.locale.searchableSelect.clearButtonLabel}"
1097
+ @click="${(x) => x._onClearButtonClick()}"
1098
+ @mousedown="${() => false}"
1099
+ ?disabled="${(x) => x.disabled}"
1100
+ :shape="${(x) => x.shape}"
1101
+ size="super-condensed"
1102
+ icon="close-line"
1103
+ appearance="ghost-light"
1104
+ tabindex="-1"
1105
+ ></${buttonTag}>`
1106
+ )}
1107
+ <div @mousedown="${() => false}" @click="${(x) => x._onChevronClick()}">
1108
+ ${when.when(
1109
+ (x) => x.loading,
1110
+ vividElement.html`<${progressRingTag} indeterminate size="-6"></${progressRingTag}>`
1111
+ )}
1112
+ ${when.when((x) => !x.loading, chevronTemplate)}
1113
+ </div>
811
1114
  </div>
812
- ${chevronTemplate}
813
- </div>`;
1115
+ `;
814
1116
  }
815
1117
  function setFixedDropdownVarWidth(x) {
816
- return x.open && x.fixedDropdown ? `--_select-fixed-width: ${Math.round(x.getBoundingClientRect().width)}px` : null;
1118
+ return x.open && x.fixedDropdown ? `--_searchable-select-fixed-width: ${Math.round(
1119
+ x.getBoundingClientRect().width
1120
+ )}px` : null;
817
1121
  }
818
1122
  function renderControl(context) {
819
1123
  const popupTag = context.tagFor(definition.Popup);
820
1124
  return vividElement.html`
821
- ${when.when((x) => x.label, renderLabel())}
822
- <div class="control-wrapper">
823
- ${when.when((x) => !x.multiple, selectValue(context))}
824
- <${popupTag} class="popup"
825
- style="${setFixedDropdownVarWidth}"
826
- ?open="${(x) => x.collapsible ? x.open : true}"
1125
+ ${when.when(
1126
+ (x) => x.label || x.multiple && x.maxSelected && x.maxSelected >= 1,
1127
+ vividElement.html`
1128
+ <div>
1129
+ ${when.when((x) => x.label, renderLabel())}
1130
+ ${when.when(
1131
+ (x) => x.multiple && x.maxSelected && x.maxSelected >= 1,
1132
+ renderSelectionCount()
1133
+ )}
1134
+ </div>
1135
+ `
1136
+ )}
1137
+ <span aria-live="assertive" aria-relevant="text" class="visually-hidden">
1138
+ ${(x) => x._changeDescription}
1139
+ </span>
1140
+ <div>
1141
+ ${renderFieldset(context)}
1142
+ <div class="popup-wrapper">
1143
+ <${popupTag}
827
1144
  :anchor="${(x) => x._anchor}"
1145
+ :open="${(x) => x.open}"
1146
+ class="popup"
828
1147
  placement="bottom-start"
829
- strategy="${(x) => x.fixedDropdown ? null : "absolute"}">
830
- <div class="listbox"
831
- id="${(x) => x.listboxId}"
1148
+ style="${setFixedDropdownVarWidth}"
1149
+ strategy="${(x) => x.fixedDropdown ? "fixed" : "absolute"}">
1150
+ <div
1151
+ class="listbox"
832
1152
  role="listbox"
833
1153
  aria-multiselectable="${(x) => x.multiple}"
834
- aria-label="${(x) => x.multiple && !x.label && x.ariaLabel ? x.ariaLabel : null}"
835
- aria-labelledby="${(x) => x.multiple && x.label ? "label" : null}"
836
- ?disabled="${(x) => x.disabled}"
837
- ?hidden="${(x) => x.collapsible ? !x.open : false}"
838
- ${ref.ref("listbox")}>
839
- ${when.when((x) => x.placeholder, renderPlaceholder(context))}
1154
+ aria-required="${(x) => x.required}"
1155
+ ${ref.ref("_listbox")}
1156
+ @click="${(x, c) => x._onListboxClick(c.event)}"
1157
+ @mousedown="${() => false}"
1158
+ >
840
1159
  <slot
841
1160
  ${slotted.slotted({
842
- filter: listbox.Listbox.slottedOptionFilter,
1161
+ filter: option.isListboxOption,
843
1162
  flatten: true,
844
- property: "slottedOptions"
1163
+ property: "_slottedOptions"
845
1164
  })}>
846
1165
  </slot>
847
- </div>
1166
+ ${when.when(
1167
+ (x) => x._filteredOptions.length === 0,
1168
+ vividElement.html`<div class="empty-message">
1169
+ ${when.when(
1170
+ (x) => x.loading,
1171
+ vividElement.html`<slot name="loading-options">
1172
+ ${(x) => x.locale.searchableSelect.loadingOptionsMessage}
1173
+ </slot>`
1174
+ )}
1175
+ ${when.when(
1176
+ (x) => !x.loading && x.searchText === "",
1177
+ vividElement.html`<slot name="no-options">
1178
+ ${(x) => x.locale.searchableSelect.noOptionsMessage}
1179
+ </slot>`
1180
+ )}
1181
+ ${when.when(
1182
+ (x) => !x.loading && x.searchText !== "",
1183
+ vividElement.html`<slot name="no-matches">
1184
+ ${(x) => x.locale.searchableSelect.noMatchesMessage}
1185
+ </slot>`
1186
+ )}
1187
+ </div>`
1188
+ )}
1189
+ </div>
848
1190
  </${popupTag}>
849
1191
  </div>
850
- `;
851
- }
852
- function ifNotFromFeedback(handler) {
853
- return (x, c) => {
854
- if (!c.event.composedPath().includes(x._feedbackWrapper)) {
855
- return handler(x, c.event);
856
- }
857
- return true;
858
- };
1192
+ </div>
1193
+ `;
859
1194
  }
860
- const SelectTemplate = (context) => {
1195
+ const SearchableSelectTemplate = (context) => {
1196
+ const optionTagTag = context.tagFor(OptionTag);
861
1197
  return vividElement.html`
862
1198
  <template
863
- class="base"
864
- ${hostSemantics.applyHostSemantics({
865
- role: "combobox",
866
- ariaLabel: (x) => x.ariaLabel ?? x.label,
867
- ariaHasPopup: (x) => x.collapsible ? "listbox" : "false",
868
- ariaExpanded: (x) => x.open,
869
- ariaDisabled: (x) => x.disabled
870
- })}
871
- aria-controls="${(x) => x.listboxId}"
872
- aria-activedescendant="${(x) => x._activeDescendant}"
873
- tabindex="${(x) => !x.disabled ? "0" : null}"
874
- @click="${ifNotFromFeedback((x, e) => x.clickHandler(e))}"
875
- @focusin="${ifNotFromFeedback((x, e) => x.focusinHandler(e))}"
876
- @focusout="${ifNotFromFeedback(
877
- (x, e) => x.focusoutHandler(e)
878
- )}"
879
- @keydown="${ifNotFromFeedback((x, e) => {
880
- x.open && index.handleEscapeKeyAndStopPropogation(e);
881
- return x.keydownHandler(e);
882
- })}"
883
- @mousedown="${ifNotFromFeedback(
884
- (x, e) => x.mousedownHandler(e)
885
- )}"
1199
+ :_optionTagTagName="${() => optionTagTag}"
1200
+ @mousedown="${(x, c) => x._onMouseDown(c.event)}"
886
1201
  >
887
- ${renderControl(context)}
888
- <div class="feedback-wrapper" ${ref.ref("_feedbackWrapper")}>
889
- ${formElements.getFeedbackTemplate(context)}
1202
+ <div class="control-wrapper">
1203
+ ${renderControl(context)} ${(x) => x._getFeedbackTemplate(context)}
890
1204
  </div>
891
1205
  </template>
892
1206
  `;
893
1207
  };
894
1208
 
895
- const selectDefinition = vividElement.defineVividComponent(
896
- "select",
897
- exports.Select,
898
- SelectTemplate,
899
- [definition.popupDefinition, definition$2.iconDefinition, definition$3.listboxOptionDefinition],
1209
+ const getClasses = ({ shape, connotation, disabled, removable }) => classNames.classNames(
1210
+ "base",
1211
+ ["disabled", disabled],
1212
+ ["removable", removable],
1213
+ [`shape-${shape}`, Boolean(shape)],
1214
+ [`connotation-${connotation}`, Boolean(connotation)]
1215
+ );
1216
+ function renderRemoveButton(iconTag) {
1217
+ return vividElement.html`
1218
+ <span
1219
+ class="remove-button"
1220
+ aria-label="${(x) => x.locale.searchableSelect.removeTagButtonLabel(x.label)}"
1221
+ role="button"
1222
+ tabindex="${(x) => x.disabled ? null : 0}"
1223
+ @click="${(x) => x._onClickRemove()}"
1224
+ >
1225
+ <${iconTag} name="close-line"></${iconTag}>
1226
+ </span>
1227
+ `;
1228
+ }
1229
+ const optionTagTemplate = (context) => {
1230
+ const iconTag = context.tagFor(definition$3.Icon);
1231
+ return vividElement.html`<span class="${getClasses}" aria-disabled="${(x) => x.disabled}">
1232
+ <slot name="icon" aria-hidden="true">
1233
+ ${when.when(
1234
+ (x) => x.hasIconPlaceholder,
1235
+ vividElement.html`<div class="icon-placeholder"></div>`
1236
+ )}
1237
+ </slot>
1238
+ ${when.when(
1239
+ (x) => x.label,
1240
+ (x) => vividElement.html`<span class="label">${x.label}</span>`
1241
+ )}
1242
+ ${when.when((x) => x.removable, renderRemoveButton(iconTag))}
1243
+ </span>`;
1244
+ };
1245
+
1246
+ const optionTagDefinition = vividElement.defineVividComponent(
1247
+ "option-tag",
1248
+ OptionTag,
1249
+ optionTagTemplate,
1250
+ [definition$3.iconDefinition],
1251
+ {
1252
+ styles: [optionTagStyles],
1253
+ shadowOptions: {
1254
+ delegatesFocus: true
1255
+ }
1256
+ }
1257
+ );
1258
+ const searchableSelectDefinition = vividElement.defineVividComponent(
1259
+ "searchable-select",
1260
+ SearchableSelect,
1261
+ SearchableSelectTemplate,
1262
+ [
1263
+ definition$1.buttonDefinition,
1264
+ definition.popupDefinition,
1265
+ definition$3.iconDefinition,
1266
+ optionTagDefinition,
1267
+ definition$2.progressRingDefinition,
1268
+ mixins.feedbackMessageDefinition
1269
+ ],
900
1270
  {
901
1271
  styles
902
1272
  }
903
1273
  );
904
- const registerSelect = vividElement.createRegisterFunction(selectDefinition);
1274
+ const registerSearchableSelect = vividElement.createRegisterFunction(
1275
+ searchableSelectDefinition
1276
+ );
905
1277
 
906
- exports.registerSelect = registerSelect;
907
- exports.selectDefinition = selectDefinition;
1278
+ exports.SearchableSelect = SearchableSelect;
1279
+ exports.registerSearchableSelect = registerSearchableSelect;