@vonage/vivid 4.23.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 (396) hide show
  1. package/custom-elements.json +21830 -14295
  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 +1510 -32
  31. package/lib/file-picker/locale.d.ts +1 -0
  32. package/lib/header/header.d.ts +6 -0
  33. package/lib/icon/icon.d.ts +1 -0
  34. package/lib/icon/icon.template.d.ts +2 -1
  35. package/lib/menu/menu.d.ts +16 -7
  36. package/lib/menu/name.d.ts +1 -0
  37. package/lib/menu-item/menu-item.d.ts +14 -2
  38. package/lib/nav/nav.d.ts +6 -0
  39. package/lib/nav-disclosure/nav-disclosure.d.ts +13 -0
  40. package/lib/nav-item/nav-item.d.ts +405 -3
  41. package/lib/note/note.d.ts +6 -0
  42. package/lib/number-field/number-field.d.ts +1857 -36
  43. package/lib/option/option.d.ts +12 -0
  44. package/lib/progress/progress.d.ts +6 -0
  45. package/lib/progress-ring/progress-ring.d.ts +6 -0
  46. package/lib/radio/radio.d.ts +1137 -4
  47. package/lib/radio-group/radio-group.d.ts +20 -2
  48. package/lib/range-slider/range-slider.d.ts +752 -5
  49. package/lib/rich-text-editor/definition.d.ts +2 -2
  50. package/lib/rich-text-editor/facades/vivid-prose-mirror.facade.d.ts +3 -1
  51. package/lib/rich-text-editor/locale.d.ts +10 -0
  52. package/lib/rich-text-editor/menubar/menubar.d.ts +340 -1
  53. package/lib/rich-text-editor/rich-text-editor.d.ts +352 -2
  54. package/lib/searchable-select/locale.d.ts +1 -0
  55. package/lib/searchable-select/option-tag.d.ts +6 -0
  56. package/lib/searchable-select/searchable-select.d.ts +1857 -35
  57. package/lib/select/select.d.ts +1843 -28
  58. package/lib/selectable-box/selectable-box.d.ts +6 -0
  59. package/lib/slider/slider.d.ts +384 -2
  60. package/lib/split-button/split-button.d.ts +18 -0
  61. package/lib/switch/switch.d.ts +386 -3
  62. package/lib/tab/tab.d.ts +18 -1
  63. package/lib/tab-panel/tab-panel.d.ts +6 -0
  64. package/lib/tabs/tabs.d.ts +5 -21
  65. package/lib/tag/tag.d.ts +12 -0
  66. package/lib/tag-group/tag-group.d.ts +6 -0
  67. package/lib/text-area/text-area.d.ts +2174 -19
  68. package/lib/text-field/text-field.d.ts +2195 -31
  69. package/lib/time-picker/time-picker.d.ts +839 -106
  70. package/lib/toggletip/toggletip.d.ts +10 -4
  71. package/lib/tooltip/tooltip.d.ts +10 -4
  72. package/lib/tree-item/tree-item.d.ts +12 -0
  73. package/lib/tree-view/tree-view.d.ts +6 -0
  74. package/lib/video-player/video-player.d.ts +6 -0
  75. package/lib/visually-hidden/definition.d.ts +4 -0
  76. package/lib/visually-hidden/visually-hidden.d.ts +3 -0
  77. package/lib/visually-hidden/visually-hidden.template.d.ts +3 -0
  78. package/locales/de-DE.cjs +47 -1
  79. package/locales/de-DE.js +47 -1
  80. package/locales/en-GB.cjs +47 -1
  81. package/locales/en-GB.js +47 -1
  82. package/locales/en-US.cjs +47 -1
  83. package/locales/en-US.js +47 -1
  84. package/locales/ja-JP.cjs +47 -1
  85. package/locales/ja-JP.js +47 -1
  86. package/locales/zh-CN.cjs +47 -1
  87. package/locales/zh-CN.js +47 -1
  88. package/menu/index.cjs +1 -1
  89. package/menu/index.js +1 -1
  90. package/nav/index.cjs +1 -1
  91. package/nav/index.js +1 -1
  92. package/nav-disclosure/index.cjs +1 -1
  93. package/nav-disclosure/index.js +1 -1
  94. package/nav-item/index.cjs +1 -1
  95. package/nav-item/index.js +1 -1
  96. package/note/index.cjs +1 -1
  97. package/note/index.js +1 -1
  98. package/number-field/index.cjs +1 -1
  99. package/number-field/index.js +1 -1
  100. package/option/index.cjs +1 -1
  101. package/option/index.js +1 -1
  102. package/package.json +1 -1
  103. package/pagination/index.cjs +1 -1
  104. package/pagination/index.js +1 -1
  105. package/popup/index.cjs +1 -1
  106. package/popup/index.js +1 -1
  107. package/progress/index.cjs +1 -1
  108. package/progress/index.js +1 -1
  109. package/progress-ring/index.cjs +1 -1
  110. package/progress-ring/index.js +1 -1
  111. package/radio/index.cjs +1 -1
  112. package/radio/index.js +1 -1
  113. package/radio-group/index.cjs +1 -1
  114. package/radio-group/index.js +1 -1
  115. package/range-slider/index.cjs +1 -1
  116. package/range-slider/index.js +1 -1
  117. package/rich-text-editor/index.cjs +1 -1
  118. package/rich-text-editor/index.js +1 -1
  119. package/searchable-select/index.cjs +1 -1
  120. package/searchable-select/index.js +1 -1
  121. package/select/index.cjs +1 -1
  122. package/select/index.js +1 -1
  123. package/selectable-box/index.cjs +1 -1
  124. package/selectable-box/index.js +1 -1
  125. package/shared/affix.cjs +13 -7
  126. package/shared/affix.js +13 -8
  127. package/shared/aria/delegates-aria.d.ts +6 -0
  128. package/shared/aria/host-semantics.d.ts +6 -0
  129. package/shared/breadcrumb-item.cjs +2 -5
  130. package/shared/breadcrumb-item.js +2 -5
  131. package/shared/button.cjs +19 -14
  132. package/shared/button.js +19 -14
  133. package/shared/calendar-picker.template.cjs +3 -3
  134. package/shared/calendar-picker.template.js +1 -1
  135. package/shared/char-count.cjs +92 -0
  136. package/shared/char-count.js +90 -0
  137. package/shared/definition.js +1 -1
  138. package/shared/definition10.js +1 -1
  139. package/shared/definition11.cjs +27 -44
  140. package/shared/definition11.js +28 -45
  141. package/shared/definition12.cjs +1 -1
  142. package/shared/definition12.js +2 -2
  143. package/shared/definition13.js +1 -1
  144. package/shared/definition14.cjs +53 -22
  145. package/shared/definition14.js +54 -23
  146. package/shared/definition15.cjs +31 -36
  147. package/shared/definition15.js +30 -36
  148. package/shared/definition16.cjs +43 -63
  149. package/shared/definition16.js +42 -63
  150. package/shared/definition17.cjs +12 -5
  151. package/shared/definition17.js +12 -5
  152. package/shared/definition18.cjs +10 -14
  153. package/shared/definition18.js +9 -14
  154. package/shared/definition19.cjs +85 -100
  155. package/shared/definition19.js +75 -91
  156. package/shared/definition2.js +1 -1
  157. package/shared/definition20.cjs +15 -20
  158. package/shared/definition20.js +14 -20
  159. package/shared/definition21.cjs +22 -3
  160. package/shared/definition21.js +23 -4
  161. package/shared/definition22.cjs +12 -6
  162. package/shared/definition22.js +13 -7
  163. package/shared/definition23.cjs +5 -38
  164. package/shared/definition23.js +5 -37
  165. package/shared/definition24.cjs +2 -7
  166. package/shared/definition24.js +3 -8
  167. package/shared/definition25.js +1 -1
  168. package/shared/definition26.cjs +160 -163
  169. package/shared/definition26.js +159 -163
  170. package/shared/definition27.cjs +1 -1
  171. package/shared/definition27.js +2 -2
  172. package/shared/definition28.cjs +32 -17
  173. package/shared/definition28.js +33 -18
  174. package/shared/definition29.js +1 -1
  175. package/shared/definition3.js +1 -1
  176. package/shared/definition30.cjs +96 -482
  177. package/shared/definition30.js +99 -482
  178. package/shared/definition31.cjs +334 -57
  179. package/shared/definition31.js +333 -56
  180. package/shared/definition32.cjs +104 -19
  181. package/shared/definition32.js +105 -20
  182. package/shared/definition33.cjs +67 -15
  183. package/shared/definition33.js +66 -14
  184. package/shared/definition34.cjs +15 -50
  185. package/shared/definition34.js +14 -49
  186. package/shared/definition35.cjs +28 -397
  187. package/shared/definition35.js +27 -397
  188. package/shared/definition36.cjs +404 -54
  189. package/shared/definition36.js +404 -55
  190. package/shared/definition37.cjs +57 -234
  191. package/shared/definition37.js +57 -233
  192. package/shared/definition38.cjs +221 -66
  193. package/shared/definition38.js +220 -65
  194. package/shared/definition39.cjs +52 -44
  195. package/shared/definition39.js +51 -43
  196. package/shared/definition4.cjs +31 -24
  197. package/shared/definition4.js +33 -26
  198. package/shared/definition40.cjs +56 -266
  199. package/shared/definition40.js +55 -265
  200. package/shared/definition41.cjs +285 -142
  201. package/shared/definition41.js +285 -142
  202. package/shared/definition42.cjs +156 -564
  203. package/shared/definition42.js +156 -565
  204. package/shared/definition43.cjs +557 -14317
  205. package/shared/definition43.js +556 -14316
  206. package/shared/definition44.cjs +14418 -1085
  207. package/shared/definition44.js +14416 -1085
  208. package/shared/definition45.cjs +1049 -671
  209. package/shared/definition45.js +1050 -672
  210. package/shared/definition46.cjs +848 -113
  211. package/shared/definition46.js +847 -112
  212. package/shared/definition47.cjs +125 -90
  213. package/shared/definition47.js +124 -89
  214. package/shared/definition48.cjs +88 -455
  215. package/shared/definition48.js +87 -454
  216. package/shared/definition49.cjs +466 -109
  217. package/shared/definition49.js +466 -109
  218. package/shared/definition5.cjs +8 -7
  219. package/shared/definition5.js +6 -5
  220. package/shared/definition50.cjs +106 -106
  221. package/shared/definition50.js +105 -105
  222. package/shared/definition51.cjs +136 -15
  223. package/shared/definition51.js +135 -14
  224. package/shared/definition52.cjs +16 -115
  225. package/shared/definition52.js +15 -114
  226. package/shared/definition53.cjs +78 -490
  227. package/shared/definition53.js +77 -488
  228. package/shared/definition54.cjs +445 -23
  229. package/shared/definition54.js +443 -22
  230. package/shared/definition55.cjs +22 -136
  231. package/shared/definition55.js +21 -135
  232. package/shared/definition56.cjs +95 -291
  233. package/shared/definition56.js +95 -292
  234. package/shared/definition57.cjs +192 -480
  235. package/shared/definition57.js +190 -479
  236. package/shared/definition58.cjs +411 -24
  237. package/shared/definition58.js +410 -24
  238. package/shared/definition59.cjs +27 -144
  239. package/shared/definition59.js +27 -143
  240. package/shared/definition6.js +1 -1
  241. package/shared/definition60.cjs +83 -54
  242. package/shared/definition60.js +82 -53
  243. package/shared/definition61.cjs +78 -166
  244. package/shared/definition61.js +77 -164
  245. package/shared/definition62.cjs +143 -232
  246. package/shared/definition62.js +141 -231
  247. package/shared/definition63.cjs +234 -69417
  248. package/shared/definition63.js +233 -69416
  249. package/shared/definition64.cjs +69454 -28
  250. package/shared/definition64.js +69453 -27
  251. package/shared/definition65.cjs +28 -2168
  252. package/shared/definition65.js +27 -2166
  253. package/shared/definition66.cjs +27 -0
  254. package/shared/definition66.js +23 -0
  255. package/shared/definition67.cjs +2195 -0
  256. package/shared/definition67.js +2190 -0
  257. package/shared/definition7.cjs +11 -2
  258. package/shared/definition7.js +12 -3
  259. package/shared/definition8.cjs +24 -11
  260. package/shared/definition8.js +26 -13
  261. package/shared/definition9.cjs +1 -2
  262. package/shared/definition9.js +2 -3
  263. package/shared/delegates-aria.js +1 -1
  264. package/shared/deprecation/replaced-props.d.ts +20 -0
  265. package/shared/divider.cjs +41 -0
  266. package/shared/divider.js +38 -0
  267. package/shared/feedback/feedback-message.d.ts +345 -0
  268. package/shared/feedback/locale.d.ts +4 -0
  269. package/{lib/text-anchor/text-anchor.d.ts → shared/feedback/mixins.d.ts} +62 -39
  270. package/shared/form-associated.cjs +124 -100
  271. package/shared/form-associated.js +125 -101
  272. package/shared/form-element.cjs +84 -0
  273. package/shared/form-element.js +82 -0
  274. package/shared/foundation/button/button.d.ts +378 -2
  275. package/shared/foundation/form-associated/form-associated.d.ts +753 -49
  276. package/shared/foundation/listbox/listbox.d.ts +1 -1
  277. package/shared/foundation/vivid-element/vivid-element.d.ts +14 -0
  278. package/shared/host-semantics.js +1 -1
  279. package/shared/key-codes.js +1 -1
  280. package/shared/linkable.cjs +70 -0
  281. package/shared/linkable.js +68 -0
  282. package/shared/localization/Locale.d.ts +16 -0
  283. package/shared/mixins.cjs +306 -0
  284. package/shared/mixins.js +300 -0
  285. package/shared/patterns/affix.d.ts +16 -1
  286. package/shared/patterns/anchored.d.ts +20 -8
  287. package/shared/patterns/char-count/char-count.d.ts +351 -0
  288. package/shared/patterns/char-count/index.d.ts +1 -0
  289. package/shared/patterns/char-count/locale.d.ts +4 -0
  290. package/shared/patterns/form-elements/form-element.d.ts +744 -0
  291. package/shared/patterns/form-elements/index.d.ts +3 -1
  292. package/shared/patterns/form-elements/with-error-text.d.ts +1122 -0
  293. package/shared/patterns/form-elements/with-success-text.d.ts +341 -0
  294. package/shared/patterns/index.d.ts +2 -0
  295. package/shared/patterns/linkable.d.ts +394 -0
  296. package/shared/patterns/localized.d.ts +6 -0
  297. package/shared/patterns/trapped-focus.d.ts +6 -0
  298. package/shared/picker-field/mixins/calendar-picker.d.ts +420 -52
  299. package/shared/picker-field/mixins/calendar-picker.template.d.ts +420 -52
  300. package/shared/picker-field/mixins/inline-time-picker/inline-time-picker.d.ts +6 -0
  301. package/shared/picker-field/mixins/min-max-calendar-picker.d.ts +843 -107
  302. package/shared/picker-field/mixins/single-date-picker.d.ts +1259 -155
  303. package/shared/picker-field/mixins/single-value-picker.d.ts +417 -49
  304. package/shared/picker-field/mixins/time-selection-picker.d.ts +842 -106
  305. package/shared/picker-field/mixins/time-selection-picker.template.d.ts +839 -103
  306. package/shared/picker-field/picker-field.d.ts +1491 -15
  307. package/shared/picker-field.template.cjs +13 -22
  308. package/shared/picker-field.template.js +14 -23
  309. package/shared/repeat.js +1 -1
  310. package/shared/slider.template.cjs +1 -1
  311. package/shared/slider.template.js +1 -1
  312. package/shared/time-selection-picker.template.cjs +10 -15
  313. package/shared/time-selection-picker.template.js +10 -16
  314. package/shared/vivid-element.cjs +53 -4
  315. package/shared/vivid-element.js +53 -3
  316. package/shared/with-error-text.cjs +56 -0
  317. package/shared/with-error-text.js +54 -0
  318. package/shared/with-success-text.cjs +23 -0
  319. package/shared/with-success-text.js +21 -0
  320. package/side-drawer/index.cjs +1 -1
  321. package/side-drawer/index.js +1 -1
  322. package/slider/index.cjs +1 -1
  323. package/slider/index.js +1 -1
  324. package/split-button/index.cjs +1 -1
  325. package/split-button/index.js +1 -1
  326. package/styles/core/all.css +1 -1
  327. package/styles/core/theme.css +1 -1
  328. package/styles/core/typography.css +1 -1
  329. package/styles/tokens/theme-dark.css +4 -4
  330. package/styles/tokens/theme-light.css +4 -4
  331. package/styles/tokens/vivid-2-compat.css +1 -1
  332. package/switch/index.cjs +1 -1
  333. package/switch/index.js +1 -1
  334. package/tab/index.cjs +1 -1
  335. package/tab/index.js +1 -1
  336. package/tab-panel/index.cjs +1 -1
  337. package/tab-panel/index.js +1 -1
  338. package/tabs/index.cjs +1 -1
  339. package/tabs/index.js +1 -1
  340. package/tag/index.cjs +1 -1
  341. package/tag/index.js +1 -1
  342. package/tag-group/index.cjs +1 -1
  343. package/tag-group/index.js +1 -1
  344. package/text-area/index.cjs +1 -1
  345. package/text-area/index.js +1 -1
  346. package/text-field/index.cjs +1 -1
  347. package/text-field/index.js +1 -1
  348. package/time-picker/index.cjs +1 -1
  349. package/time-picker/index.js +1 -1
  350. package/toggletip/index.cjs +1 -1
  351. package/toggletip/index.js +1 -1
  352. package/tooltip/index.cjs +1 -1
  353. package/tooltip/index.js +1 -1
  354. package/tree-item/index.cjs +1 -1
  355. package/tree-item/index.js +1 -1
  356. package/tree-view/index.cjs +1 -1
  357. package/tree-view/index.js +1 -1
  358. package/video-player/index.cjs +1 -1
  359. package/video-player/index.js +1 -1
  360. package/visually-hidden/index.cjs +5 -0
  361. package/visually-hidden/index.js +3 -0
  362. package/vivid.api.json +762 -1478
  363. package/lib/checkbox/checkbox.form-associated.d.ts +0 -11
  364. package/lib/file-picker/file-picker.form-associated.d.ts +0 -11
  365. package/lib/number-field/number-field.form-associated.d.ts +0 -11
  366. package/lib/radio/radio.form-associated.d.ts +0 -13
  367. package/lib/range-slider/range-slider.form-associated.d.ts +0 -11
  368. package/lib/searchable-select/searchable-select.form-associated.d.ts +0 -11
  369. package/lib/select/select.form-associated.d.ts +0 -11
  370. package/lib/slider/slider.form-associated.d.ts +0 -11
  371. package/lib/switch/switch.form-associated.d.ts +0 -11
  372. package/lib/text-anchor/definition.d.ts +0 -2
  373. package/lib/text-anchor/text-anchor.template.d.ts +0 -3
  374. package/lib/text-area/text-area.form-associated.d.ts +0 -11
  375. package/lib/text-field/text-field.form-associated.d.ts +0 -11
  376. package/shared/anchor.cjs +0 -49
  377. package/shared/anchor.js +0 -47
  378. package/shared/apply-mixins.cjs +0 -23
  379. package/shared/apply-mixins.js +0 -21
  380. package/shared/applyMixinsWithObservables.cjs +0 -15
  381. package/shared/applyMixinsWithObservables.js +0 -13
  382. package/shared/direction.cjs +0 -17
  383. package/shared/direction.js +0 -15
  384. package/shared/form-elements.cjs +0 -209
  385. package/shared/form-elements.js +0 -202
  386. package/shared/foundation/anchor/anchor.d.ts +0 -11
  387. package/shared/foundation/utilities/apply-mixins.d.ts +0 -1
  388. package/shared/patterns/form-elements/form-elements.d.ts +0 -58
  389. package/shared/picker-field/picker-field.form-associated.d.ts +0 -11
  390. package/shared/text-anchor.cjs +0 -38
  391. package/shared/text-anchor.js +0 -36
  392. package/shared/text-anchor.template.cjs +0 -35
  393. package/shared/text-anchor.template.js +0 -33
  394. package/shared/utils/applyMixinsWithObservables.d.ts +0 -1
  395. package/text-anchor/index.cjs +0 -17
  396. package/text-anchor/index.js +0 -15
@@ -1,901 +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 for="control" class="label" id="label">
784
- ${(x) => x.label}
785
- </label>`;
964
+ return vividElement.html`
965
+ <label for="control" class="label" id="label"> ${(x) => x.label} </label>
966
+ `;
786
967
  }
787
- function renderPlaceholder(context) {
788
- const optionTag = context.tagFor(option.ListboxOption);
968
+ function renderSelectionCount() {
789
969
  return vividElement.html`
790
- <${optionTag} ${ref.ref("placeholderOption")}
791
- text="${(x) => x.placeholder}" hidden disabled>
792
- </${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
+ `;
793
980
  }
794
- 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);
795
1018
  const affixIconTemplate = affix.affixIconTemplateFactory(context);
796
1019
  const chevronTemplate = definition$1.chevronTemplateFactory(context);
797
- return vividElement.html` <div
798
- class="control ${getStateClasses}"
799
- ${ref.ref("_anchor")}
800
- id="control"
801
- ?disabled="${(x) => x.disabled}"
802
- >
803
- <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
+ >
804
1036
  ${(x) => affixIconTemplate(x.icon, affix.IconWrapper.Slot)}
805
- <span class="text">${(x) => x.displayValue}</span>
806
- <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>
807
1114
  </div>
808
- ${chevronTemplate}
809
- </div>`;
1115
+ `;
810
1116
  }
811
1117
  function setFixedDropdownVarWidth(x) {
812
- 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;
813
1121
  }
814
1122
  function renderControl(context) {
815
1123
  const popupTag = context.tagFor(definition.Popup);
816
1124
  return vividElement.html`
817
- ${when.when((x) => x.label, renderLabel())}
818
- <div class="control-wrapper">
819
- ${when.when((x) => !x.multiple, selectValue(context))}
820
- <${popupTag} class="popup"
821
- style="${setFixedDropdownVarWidth}"
822
- ?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}
823
1144
  :anchor="${(x) => x._anchor}"
1145
+ :open="${(x) => x.open}"
1146
+ class="popup"
824
1147
  placement="bottom-start"
825
- strategy="${(x) => x.fixedDropdown ? null : "absolute"}">
826
- <div class="listbox"
827
- id="${(x) => x.listboxId}"
1148
+ style="${setFixedDropdownVarWidth}"
1149
+ strategy="${(x) => x.fixedDropdown ? "fixed" : "absolute"}">
1150
+ <div
1151
+ class="listbox"
828
1152
  role="listbox"
829
1153
  aria-multiselectable="${(x) => x.multiple}"
830
- ?disabled="${(x) => x.disabled}"
831
- ?hidden="${(x) => x.collapsible ? !x.open : false}"
832
- ${ref.ref("listbox")}>
833
- ${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
+ >
834
1159
  <slot
835
1160
  ${slotted.slotted({
836
- filter: listbox.Listbox.slottedOptionFilter,
1161
+ filter: option.isListboxOption,
837
1162
  flatten: true,
838
- property: "slottedOptions"
1163
+ property: "_slottedOptions"
839
1164
  })}>
840
1165
  </slot>
841
- </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>
842
1190
  </${popupTag}>
843
1191
  </div>
844
- `;
845
- }
846
- function ifNotFromFeedback(handler) {
847
- return (x, c) => {
848
- if (!c.event.composedPath().includes(x._feedbackWrapper)) {
849
- return handler(x, c.event);
850
- }
851
- return true;
852
- };
1192
+ </div>
1193
+ `;
853
1194
  }
854
- const SelectTemplate = (context) => {
1195
+ const SearchableSelectTemplate = (context) => {
1196
+ const optionTagTag = context.tagFor(OptionTag);
855
1197
  return vividElement.html`
856
1198
  <template
857
- class="base"
858
- ${hostSemantics.applyHostSemantics({
859
- role: "combobox",
860
- ariaLabel: (x) => x.ariaLabel ?? x.label,
861
- ariaHasPopup: (x) => x.collapsible ? "listbox" : "false",
862
- ariaExpanded: (x) => x.open,
863
- ariaDisabled: (x) => x.disabled
864
- })}
865
- aria-controls="${(x) => x.listboxId}"
866
- aria-activedescendant="${(x) => x._activeDescendant}"
867
- tabindex="${(x) => !x.disabled ? "0" : null}"
868
- @click="${ifNotFromFeedback((x, e) => x.clickHandler(e))}"
869
- @focusin="${ifNotFromFeedback((x, e) => x.focusinHandler(e))}"
870
- @focusout="${ifNotFromFeedback(
871
- (x, e) => x.focusoutHandler(e)
872
- )}"
873
- @keydown="${ifNotFromFeedback((x, e) => {
874
- x.open && index.handleEscapeKeyAndStopPropogation(e);
875
- return x.keydownHandler(e);
876
- })}"
877
- @mousedown="${ifNotFromFeedback(
878
- (x, e) => x.mousedownHandler(e)
879
- )}"
1199
+ :_optionTagTagName="${() => optionTagTag}"
1200
+ @mousedown="${(x, c) => x._onMouseDown(c.event)}"
880
1201
  >
881
- ${renderControl(context)}
882
- <div class="feedback-wrapper" ${ref.ref("_feedbackWrapper")}>
883
- ${formElements.getFeedbackTemplate(context)}
1202
+ <div class="control-wrapper">
1203
+ ${renderControl(context)} ${(x) => x._getFeedbackTemplate(context)}
884
1204
  </div>
885
1205
  </template>
886
1206
  `;
887
1207
  };
888
1208
 
889
- const selectDefinition = vividElement.defineVividComponent(
890
- "select",
891
- exports.Select,
892
- SelectTemplate,
893
- [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
+ ],
894
1270
  {
895
1271
  styles
896
1272
  }
897
1273
  );
898
- const registerSelect = vividElement.createRegisterFunction(selectDefinition);
1274
+ const registerSearchableSelect = vividElement.createRegisterFunction(
1275
+ searchableSelectDefinition
1276
+ );
899
1277
 
900
- exports.registerSelect = registerSelect;
901
- exports.selectDefinition = selectDefinition;
1278
+ exports.SearchableSelect = SearchableSelect;
1279
+ exports.registerSearchableSelect = registerSearchableSelect;