qc-trousse-sdg 1.4.0-develop.0 → 1.4.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 (292) hide show
  1. package/README.md +22 -5
  2. package/dist/css/qc-sdg-design-tokens.min.css +1 -1
  3. package/dist/css/qc-sdg-no-grid.min.css +1 -1
  4. package/dist/css/qc-sdg.min.css +1 -1
  5. package/dist/fonts/open-sans-v43-latin-500.woff2 +0 -0
  6. package/dist/fonts/open-sans-v43-latin-500italic.woff2 +0 -0
  7. package/dist/fonts/open-sans-v43-latin-600.woff2 +0 -0
  8. package/dist/fonts/open-sans-v43-latin-600italic.woff2 +0 -0
  9. package/dist/fonts/open-sans-v43-latin-700.woff2 +0 -0
  10. package/dist/fonts/open-sans-v43-latin-700italic.woff2 +0 -0
  11. package/dist/fonts/open-sans-v43-latin-italic.woff2 +0 -0
  12. package/dist/fonts/open-sans-v43-latin-regular.woff2 +0 -0
  13. package/dist/fonts/roboto-mono-v30-latin-500.woff2 +0 -0
  14. package/dist/fonts/roboto-mono-v30-latin-500italic.woff2 +0 -0
  15. package/dist/fonts/roboto-mono-v30-latin-600.woff2 +0 -0
  16. package/dist/fonts/roboto-mono-v30-latin-600italic.woff2 +0 -0
  17. package/dist/fonts/roboto-mono-v30-latin-700.woff2 +0 -0
  18. package/dist/fonts/roboto-mono-v30-latin-700italic.woff2 +0 -0
  19. package/dist/fonts/roboto-mono-v30-latin-italic.woff2 +0 -0
  20. package/dist/fonts/roboto-mono-v30-latin-regular.woff2 +0 -0
  21. package/dist/fonts/roboto-v48-latin-500.woff2 +0 -0
  22. package/dist/fonts/roboto-v48-latin-500italic.woff2 +0 -0
  23. package/dist/fonts/roboto-v48-latin-600.woff2 +0 -0
  24. package/dist/fonts/roboto-v48-latin-600italic.woff2 +0 -0
  25. package/dist/fonts/roboto-v48-latin-700.woff2 +0 -0
  26. package/dist/fonts/roboto-v48-latin-700italic.woff2 +0 -0
  27. package/dist/fonts/roboto-v48-latin-italic.woff2 +0 -0
  28. package/dist/fonts/roboto-v48-latin-regular.woff2 +0 -0
  29. package/dist/img/icon/adresse.svg +4 -0
  30. package/dist/img/icon/arrow-up.svg +3 -0
  31. package/dist/img/icon/calendar.svg +1 -0
  32. package/dist/img/icon/checkmark.svg +3 -0
  33. package/dist/img/icon/chevron-up-thin.svg +5 -0
  34. package/dist/img/{chevron-white.svg → icon/chevron-up.svg} +1 -1
  35. package/{public/img → dist/img/icon}/clipboard.svg +3 -3
  36. package/dist/img/icon/clock.svg +1 -0
  37. package/dist/img/icon/email.svg +1 -0
  38. package/dist/img/icon/error.svg +1 -0
  39. package/{public/img/exclamation-white.svg → dist/img/icon/exclamation.svg} +2 -2
  40. package/{public/img → dist/img/icon}/external-link.svg +2 -2
  41. package/dist/img/icon/information.svg +1 -0
  42. package/dist/img/icon/ligth-bulb.svg +1 -0
  43. package/{public/img → dist/img/icon}/minus.svg +1 -1
  44. package/dist/img/icon/note.svg +1 -0
  45. package/dist/img/icon/phone.svg +1 -0
  46. package/dist/img/{plus.svg → icon/plus.svg} +1 -1
  47. package/{public/img → dist/img/icon}/question-mark.svg +2 -2
  48. package/dist/img/icon/search-thin.svg +10 -0
  49. package/dist/img/icon/search.svg +1 -0
  50. package/dist/img/icon/success.svg +1 -0
  51. package/dist/img/icon/user.svg +6 -0
  52. package/dist/img/icon/warning.svg +1 -0
  53. package/dist/img/icon/website.svg +1 -0
  54. package/dist/img/icon/xclose.svg +1 -0
  55. package/dist/js/qc-sdg.min.js +1 -1
  56. package/package.json +11 -3
  57. package/playwright.config.ts +79 -0
  58. package/plugins/buildDevDoc.js +36 -0
  59. package/plugins/buildHtmlDoc.js +43 -0
  60. package/plugins/buildTestFixtures.js +37 -0
  61. package/public/css/qc-doc-sdg.css +4 -67
  62. package/public/css/qc-sdg-design-tokens.css +17 -0
  63. package/public/css/qc-sdg-no-grid.css +2001 -1108
  64. package/public/css/qc-sdg.css +1999 -1106
  65. package/public/img/checkmark.svg +3 -0
  66. package/public/img/question.svg +10 -0
  67. package/public/index.html +3104 -1387
  68. package/public/js/qc-doc-sdg.js +5705 -285
  69. package/public/js/qc-sdg.js +5660 -1415
  70. package/rollup.config.js +67 -41
  71. package/scripts/buildImagesMap.js +85 -0
  72. package/scripts/check-release-note.sh +11 -0
  73. package/scripts/compile-doc.sh +4 -0
  74. package/src/doc/_index.html +100 -0
  75. package/src/doc/_nav.html +53 -0
  76. package/src/doc/_test.html +32 -0
  77. package/src/doc/components/Code.svelte +6 -2
  78. package/src/doc/components/TopNav.svelte +8 -9
  79. package/src/doc/components/color-doc.svelte +1 -1
  80. package/src/doc/ejs/layout/index.ejs +129 -0
  81. package/src/doc/qc-doc-sdg.js +1 -2
  82. package/src/doc/scss/components/_code.scss +1 -1
  83. package/src/doc/scss/jQueryUI/_jquery-ui.autocomplete.scss +1 -0
  84. package/src/doc/scss/qc-doc-sdg.scss +1 -1
  85. package/src/doc/scss/settings/_base.scss +4 -0
  86. package/src/sdg/_components.js +9 -2
  87. package/src/sdg/{components → bases}/Icon/Icon.svelte +13 -6
  88. package/src/sdg/bases/Icon/IconDoc.ejs +129 -0
  89. package/src/sdg/{components → bases}/Icon/IconWC.svelte +3 -1
  90. package/src/sdg/bases/Icon/Test/IconEmbeddedTest.html +1 -0
  91. package/src/sdg/bases/Icon/Test/IconEmbeddedTest.svelte +168 -0
  92. package/src/sdg/bases/Icon/Test/iconTest.html +156 -0
  93. package/src/sdg/bases/Icon/_icon.html +254 -0
  94. package/src/sdg/bases/Icon/_icons.scss +47 -0
  95. package/src/sdg/{scss/base → bases/accessibility}/_accessibility.scss +1 -1
  96. package/src/sdg/bases/colors/_colors.html +112 -0
  97. package/src/sdg/bases/figures/_figure.html +16 -0
  98. package/src/sdg/{scss/base → bases/form}/_form.scss +10 -3
  99. package/src/sdg/bases/grid/_grid.html +118 -0
  100. package/src/sdg/bases/headings/_headings.html +18 -0
  101. package/src/sdg/bases/headings/_headings.scss +25 -0
  102. package/src/sdg/{scss/base → bases/layout}/_layout.scss +1 -4
  103. package/src/sdg/bases/links/_links.html +104 -0
  104. package/src/sdg/bases/links/_links.scss +51 -0
  105. package/src/sdg/bases/lists/_lists.html +27 -0
  106. package/src/sdg/bases/separator/_separator.html +7 -0
  107. package/src/sdg/bases/separator/_separator.scss +5 -0
  108. package/src/sdg/bases/shadings/_shadings.html +14 -0
  109. package/src/sdg/{scss/base → bases/shadings}/_shadings.scss +1 -1
  110. package/src/sdg/bases/typography/_font.html +45 -0
  111. package/src/sdg/bases/typography/_fonts.scss +162 -0
  112. package/src/sdg/bases/typography/_paragraph.html +17 -0
  113. package/src/sdg/bases/typography/_paragraph.scss +33 -0
  114. package/src/sdg/components/Alert/Alert.svelte +2 -5
  115. package/src/sdg/components/Alert/AlertWC.svelte +3 -2
  116. package/src/sdg/components/Alert/_alert.html +110 -0
  117. package/src/sdg/{scss/components → components/Alert}/_alert.scss +1 -1
  118. package/src/sdg/components/Button/Button.svelte +50 -0
  119. package/src/sdg/components/Button/ButtonWC.svelte +36 -0
  120. package/src/sdg/components/Button/Test/buttonTest.html +349 -0
  121. package/src/sdg/components/Button/_button.html +186 -0
  122. package/src/sdg/components/Button/_button.scss +202 -0
  123. package/src/sdg/components/CharCount/_charCount.html +7 -0
  124. package/src/sdg/components/Checkbox/Checkbox.svelte +77 -0
  125. package/src/sdg/components/Checkbox/CheckboxWC.svelte +49 -0
  126. package/src/sdg/components/Checkbox/_checkbox.html +86 -0
  127. package/src/sdg/components/Checkbox/_checkbox.scss +70 -0
  128. package/src/sdg/components/Checkbox/updateInput.svelte.js +23 -0
  129. package/src/sdg/components/ChoiceGroup/ChoiceGroup.svelte +56 -0
  130. package/src/sdg/components/ChoiceGroup/ChoiceGroupWC.svelte +47 -0
  131. package/src/sdg/components/ChoiceGroup/Test/ChoiceGroupeEmbededTest.svelte +261 -0
  132. package/src/sdg/components/ChoiceGroup/Test/checkboxEmbeddedTest.html +1 -0
  133. package/src/sdg/components/ChoiceGroup/Test/checkboxTest.html +253 -0
  134. package/src/sdg/components/ChoiceGroup/Test/radiosEmbeddedTest.html +1 -0
  135. package/src/sdg/components/ChoiceGroup/Test/radiosTest.html +185 -0
  136. package/src/sdg/components/ChoiceGroup/ToggleSwitchGroupWC.svelte +56 -0
  137. package/src/sdg/components/ChoiceGroup/_choiceGroup.html +285 -0
  138. package/src/sdg/components/ChoiceGroup/_choiceGroup.scss +32 -0
  139. package/src/sdg/components/ChoiceGroup/_selectionButton.scss +53 -0
  140. package/src/sdg/components/ChoiceGroup/_selectionButtons.html +130 -0
  141. package/src/sdg/components/DropdownList/DropdownList.svelte +394 -0
  142. package/src/sdg/components/DropdownList/DropdownListButton/DropdownListButton.svelte +43 -0
  143. package/src/sdg/components/DropdownList/DropdownListButton/_dropdownListButton.scss +65 -0
  144. package/src/sdg/components/DropdownList/DropdownListItems/DropdownListItems.svelte +110 -0
  145. package/src/sdg/components/DropdownList/DropdownListItems/DropdownListItemsMultiple/DropdownListItemsMultiple.svelte +185 -0
  146. package/src/sdg/components/DropdownList/DropdownListItems/DropdownListItemsMultiple/_dropdownListItemsMultiple.scss +19 -0
  147. package/src/sdg/components/DropdownList/DropdownListItems/DropdownListItemsSingle/DropdownListItemsSingle.svelte +136 -0
  148. package/src/sdg/components/DropdownList/DropdownListItems/DropdownListItemsSingle/_dropdownListItemsSingle.scss +11 -0
  149. package/src/sdg/components/DropdownList/DropdownListItems/_dropdownListItems.scss +67 -0
  150. package/src/sdg/components/DropdownList/SelectWC.svelte +158 -0
  151. package/src/sdg/components/DropdownList/Test/DropdownListEmbeddedTest.svelte +89 -0
  152. package/src/sdg/components/DropdownList/Test/dropdownListEmbeddedTest.html +1 -0
  153. package/src/sdg/components/DropdownList/Test/dropdownListTest.html +194 -0
  154. package/src/sdg/components/DropdownList/Test/dropdownListTestUtils.js +113 -0
  155. package/src/sdg/components/DropdownList/_dropdownList.scss +73 -0
  156. package/src/sdg/components/DropdownList/_select.html +212 -0
  157. package/src/sdg/components/ExternalLink/ExternalLink.svelte +1 -1
  158. package/src/sdg/components/Fieldset/Fieldset.svelte +73 -0
  159. package/src/sdg/components/Fieldset/_fieldset.scss +95 -0
  160. package/src/sdg/components/FormError/FormError.svelte +51 -0
  161. package/src/sdg/components/FormError/_formError.scss +21 -0
  162. package/src/sdg/components/FormfieldRow/_formfieldRow.html +108 -0
  163. package/src/sdg/components/IconButton/IconButton.svelte +1 -1
  164. package/src/sdg/components/IconButton/_iconButton.scss +14 -0
  165. package/src/sdg/components/Label/Label.svelte +28 -0
  166. package/src/sdg/components/Label/LabelText.svelte +4 -0
  167. package/src/sdg/components/Label/_label.scss +19 -0
  168. package/src/sdg/components/Notice/Notice.svelte +1 -2
  169. package/src/sdg/components/Notice/NoticeWC.svelte +3 -0
  170. package/src/sdg/components/Notice/_notice.html +141 -0
  171. package/src/sdg/{scss/components → components/Notice}/_notice.scss +1 -1
  172. package/src/sdg/components/PivFooter/PivFooter.svelte +8 -9
  173. package/src/sdg/components/PivFooter/PivFooterWC.svelte +6 -14
  174. package/src/sdg/components/PivFooter/_pivFooter.html +153 -0
  175. package/src/sdg/{scss/components → components/PivFooter}/_pivFooter.scss +1 -1
  176. package/src/sdg/components/PivHeader/PivHeader.svelte +47 -53
  177. package/src/sdg/components/PivHeader/PivHeaderWC.svelte +9 -20
  178. package/src/sdg/components/PivHeader/Test/pivHeaderEmbeddedTest.html +1 -0
  179. package/src/sdg/components/PivHeader/Test/pivHeaderEmbeddedTest.svelte +28 -0
  180. package/src/sdg/components/PivHeader/Test/pivHeaderTest.html +43 -0
  181. package/src/sdg/components/PivHeader/_pivHeader.html +221 -0
  182. package/src/sdg/{scss/components → components/PivHeader}/_pivHeader.scss +55 -77
  183. package/src/sdg/components/RadioButton/_radioButton.html +24 -0
  184. package/src/sdg/components/RadioButton/_radioButton.scss +29 -0
  185. package/src/sdg/components/SearchBar/SearchBar.svelte +12 -32
  186. package/src/sdg/components/SearchBar/_searchBar.html +125 -0
  187. package/src/sdg/{scss/components → components/SearchBar}/_searchBar.scss +3 -3
  188. package/src/sdg/components/SearchInput/SearchInput.svelte +26 -4
  189. package/src/sdg/components/SearchInput/SearchInputWC.svelte +3 -1
  190. package/src/sdg/components/SearchInput/_searchInput.html +85 -0
  191. package/src/sdg/{scss/components → components/SearchInput}/_searchInput.scss +27 -2
  192. package/src/sdg/components/TextField/Doc/TextFieldDemo.svelte +143 -0
  193. package/src/sdg/components/TextField/Test/TextFieldEmbededTest.svelte +129 -0
  194. package/src/sdg/components/TextField/Test/textFieldEmbeddedTest.html +1 -0
  195. package/src/sdg/components/TextField/Test/textFieldTest.html +121 -0
  196. package/src/sdg/components/TextField/TextField.svelte +171 -0
  197. package/src/sdg/components/TextField/TextFieldWC.svelte +90 -0
  198. package/src/sdg/components/TextField/_textField.html +218 -0
  199. package/src/sdg/components/TextField/_textField.scss +110 -0
  200. package/src/sdg/components/TextField/textFieldUtils.js +19 -0
  201. package/src/sdg/components/ToTop/ToTop.svelte +2 -4
  202. package/src/sdg/components/ToTop/_toTop.html +45 -0
  203. package/src/sdg/{scss/components → components/ToTop}/_toTop.scss +2 -2
  204. package/src/sdg/components/ToggleSwitch/Test/ToggleSwitchEmbeddedTest.svelte +46 -0
  205. package/src/sdg/components/ToggleSwitch/Test/toggleSwitchEmbeddedTest.html +1 -0
  206. package/src/sdg/components/ToggleSwitch/Test/toggleSwitchTest.html +34 -0
  207. package/src/sdg/components/ToggleSwitch/ToggleSwitch.svelte +34 -0
  208. package/src/sdg/components/ToggleSwitch/ToggleSwitchWC.svelte +66 -0
  209. package/src/sdg/components/ToggleSwitch/_toggleSwitch.html +160 -0
  210. package/src/sdg/components/ToggleSwitch/_toggleSwitch.scss +97 -0
  211. package/src/sdg/components/utils.js +81 -1
  212. package/src/sdg/qc-sdg-test.js +6 -0
  213. package/src/sdg/scss/lib/_functions.scss +10 -2
  214. package/src/sdg/scss/lib/_mixins.scss +63 -26
  215. package/src/sdg/scss/qc-sdg.scss +1 -1
  216. package/src/sdg/scss/qc-sgd-no-grid.scss +30 -18
  217. package/src/sdg/scss/settings/_base.scss +5 -33
  218. package/src/sdg/scss/settings/_images.scss +30 -0
  219. package/src/sdg/scss/settings/_tokens.scss +23 -0
  220. package/src/sdg/scss/utilities/_display.scss +1 -1
  221. package/src/sdg/scss/utilities/_states.scss +13 -0
  222. package/tests/button.spec.ts +11 -0
  223. package/tests/choice-group.spec.ts +36 -0
  224. package/tests/dropdown-list.spec.ts +529 -0
  225. package/tests/icon.spec.ts +19 -0
  226. package/tests/pivHeader.spec.ts +22 -0
  227. package/tests/textfield.spec.ts +21 -0
  228. package/tests/toggle-switch.spec.ts +20 -0
  229. package/dist/img/arrow-up-white.svg +0 -3
  230. package/dist/img/chevron-blue.svg +0 -3
  231. package/dist/img/clipboard.svg +0 -8
  232. package/dist/img/error-white.svg +0 -1
  233. package/dist/img/error.svg +0 -1
  234. package/dist/img/exclamation-white.svg +0 -37
  235. package/dist/img/external-link-white.svg +0 -18
  236. package/dist/img/external-link.svg +0 -10
  237. package/dist/img/facebook.svg +0 -6
  238. package/dist/img/information-white.svg +0 -1
  239. package/dist/img/information.svg +0 -1
  240. package/dist/img/linkedin.svg +0 -5
  241. package/dist/img/loupe-piv-fonce.svg +0 -1
  242. package/dist/img/minus.svg +0 -6
  243. package/dist/img/qc-sprite.svg +0 -1
  244. package/dist/img/question-mark.svg +0 -47
  245. package/dist/img/success-white.svg +0 -1
  246. package/dist/img/success.svg +0 -1
  247. package/dist/img/twitter.svg +0 -8
  248. package/dist/img/warning.svg +0 -1
  249. package/dist/img/xclose-blue.svg +0 -6
  250. package/dist/img/xclose-white.svg +0 -1
  251. package/dist/img/youtube.svg +0 -3
  252. package/public/img/ampoule.svg +0 -1
  253. package/public/img/arrow-up-white.svg +0 -3
  254. package/public/img/chevron-blue.svg +0 -3
  255. package/public/img/chevron-white.svg +0 -3
  256. package/public/img/error-white.svg +0 -1
  257. package/public/img/error.svg +0 -1
  258. package/public/img/external-link-white.svg +0 -18
  259. package/public/img/facebook.svg +0 -6
  260. package/public/img/information-white.svg +0 -1
  261. package/public/img/information.svg +0 -1
  262. package/public/img/linkedin.svg +0 -5
  263. package/public/img/logo-piv-footer-mess.png +0 -0
  264. package/public/img/loupe-piv-droite.svg +0 -1
  265. package/public/img/loupe-piv-fonce.svg +0 -1
  266. package/public/img/note.svg +0 -1
  267. package/public/img/piv-bas-MCE-theme-clair.png +0 -0
  268. package/public/img/piv-bas-MCE-theme-sombre.png +0 -0
  269. package/public/img/piv-logo-pied-de-page.svg +0 -37
  270. package/public/img/plus.svg +0 -6
  271. package/public/img/qc-sprite.svg +0 -1
  272. package/public/img/quebec-logo.svg +0 -13
  273. package/public/img/success-white.svg +0 -1
  274. package/public/img/success.svg +0 -1
  275. package/public/img/twitter.svg +0 -8
  276. package/public/img/warning.svg +0 -1
  277. package/public/img/xclose-blue.svg +0 -6
  278. package/public/img/xclose-white.svg +0 -1
  279. package/public/img/youtube.svg +0 -3
  280. package/src/doc/scss/components/_button.scss +0 -61
  281. package/src/sdg/components/PivFooter/_defaultCopyright.svelte +0 -11
  282. package/src/sdg/components/PivHeader/_defaultLinks.svelte +0 -24
  283. package/src/sdg/scss/base/_fonts.scss +0 -29
  284. package/src/sdg/scss/base/_typography.scss +0 -94
  285. package/src/sdg/scss/components/_icons.scss +0 -169
  286. package/src/sdg/scss/components/_separator.scss +0 -5
  287. /package/dist/img/{loupe-piv-droite.svg → piv-search.svg} +0 -0
  288. /package/src/sdg/{scss/base → bases/colors}/_colors.scss +0 -0
  289. /package/src/sdg/{scss/base → bases/figures}/_figure.scss +0 -0
  290. /package/src/sdg/{scss → bases}/grid/_grid-lib.scss +0 -0
  291. /package/src/sdg/{scss → bases}/grid/_grid.scss +0 -0
  292. /package/src/sdg/{scss/base → bases/lists}/_lists.scss +0 -0
@@ -0,0 +1,110 @@
1
+ <script>
2
+ import DropdownListItemsSingle from "./DropdownListItemsSingle/DropdownListItemsSingle.svelte";
3
+ import DropdownListItemsMultiple from "./DropdownListItemsMultiple/DropdownListItemsMultiple.svelte";
4
+ import {tick} from "svelte";
5
+ import {Utils} from "../../utils";
6
+
7
+ let {
8
+ id,
9
+ enableSearch,
10
+ multiple,
11
+ items,
12
+ displayedItems,
13
+ noOptionsMessage,
14
+ selectionCallbackSingle = () => {},
15
+ selectionCallbackMultiple = () => {},
16
+ handleExitSingle = () => {},
17
+ handleExitMultiple = () => {},
18
+ focusOnOuterElement = () => {},
19
+ handlePrintableCharacter = () => {},
20
+ placeholder,
21
+ } = $props()
22
+
23
+ const
24
+ precentRootFontSize = 62.5,
25
+ remRatio = 0.16
26
+ ;
27
+
28
+ let itemsComponent = $state();
29
+ let usedHeight = $derived.by(() => {
30
+ const maxItemsHeight = 336;
31
+ const searchInputTotalHeight = 56;
32
+
33
+ if (enableSearch) {
34
+ if (displayedItems.length > 7) {
35
+ return maxItemsHeight - searchInputTotalHeight - 17;
36
+ }
37
+ return maxItemsHeight - searchInputTotalHeight;
38
+ } else {
39
+ if (displayedItems.length > 8) {
40
+ return maxItemsHeight - 33;
41
+ }
42
+ return maxItemsHeight;
43
+ }
44
+ });
45
+
46
+ export function focus() {
47
+ Utils.sleep(5).then(() => {
48
+ itemsComponent?.focusOnFirstElement();
49
+ }).catch(console.error);
50
+ }
51
+
52
+ export function focusOnLastElement() {
53
+ Utils.sleep(5).then(() => {
54
+ itemsComponent?.focusOnLastElement();
55
+ }).catch(console.error);
56
+ }
57
+
58
+ export function focusOnFirstMatchingElement(value) {
59
+ if (itemsComponent && value && value.length > 0) {
60
+ Utils.sleep(5).then(() => {
61
+ itemsComponent?.focusOnFirstMatchingElement(value);
62
+ }).catch(console.error);
63
+ }
64
+ }
65
+ </script>
66
+
67
+ <div
68
+ id={id}
69
+ class="qc-dropdown-list-items"
70
+ tabindex="-1"
71
+ style="--dropdown-items-height: {usedHeight / (remRatio * precentRootFontSize)}rem;"
72
+ >
73
+ {#if multiple}
74
+ <DropdownListItemsMultiple
75
+ {items}
76
+ {displayedItems}
77
+ {noOptionsMessage}
78
+ passValue={() => {
79
+ selectionCallbackMultiple();
80
+ }}
81
+ handleExit={(key) => handleExitMultiple(key)}
82
+ focusOnOuterElement={focusOnOuterElement}
83
+ handlePrintableCharacter={handlePrintableCharacter}
84
+ bind:this={itemsComponent}
85
+ />
86
+ {:else}
87
+ <DropdownListItemsSingle
88
+ {items}
89
+ {displayedItems}
90
+ {noOptionsMessage}
91
+ selectionCallback={() => {
92
+ selectionCallbackSingle();
93
+ }}
94
+ handleExit={(key) => handleExitSingle(key)}
95
+ focusOnOuterElement={focusOnOuterElement}
96
+ handlePrintableCharacter={handlePrintableCharacter}
97
+ {placeholder}
98
+ bind:this={itemsComponent}
99
+ />
100
+ {/if}
101
+
102
+ <div class="qc-dropdown-list-no-options-container" role="status">
103
+ {#if displayedItems.length <= 0}
104
+ {#await tick() then _}
105
+ <span class="qc-dropdown-list-no-options">{@html noOptionsMessage}</span>
106
+ {/await}
107
+ {/if}
108
+ </div>
109
+
110
+ </div>
@@ -0,0 +1,185 @@
1
+ <script>
2
+ import {Utils} from "../../../utils";
3
+
4
+ let {
5
+ displayedItems,
6
+ handleExit = () => {},
7
+ selectionCallback = () => {},
8
+ focusOnOuterElement = () => {},
9
+ handlePrintableCharacter = () => {}
10
+ } = $props();
11
+
12
+ const name = Math.random().toString(36).substring(2, 15);
13
+
14
+ let displayedItemsElements = $state(new Array(displayedItems.length));
15
+
16
+ export function focusOnFirstElement() {
17
+ if (displayedItems && displayedItems.length > 0) {
18
+ if (displayedItems[0].disabled) {
19
+ displayedItemsElements[0].closest("li").focus();
20
+ } else {
21
+ displayedItemsElements[0].focus();
22
+ }
23
+ }
24
+ }
25
+
26
+ export function focusOnLastElement() {
27
+ if (displayedItems && displayedItems.length > 0) {
28
+ if (displayedItems[displayedItems.length - 1].disabled) {
29
+ displayedItemsElements[displayedItemsElements.length - 1].closest("li").focus();
30
+ } else {
31
+ displayedItemsElements[displayedItemsElements.length - 1].focus();
32
+ }
33
+ }
34
+ }
35
+
36
+ export function focusOnFirstMatchingElement(value) {
37
+ if (displayedItemsElements && displayedItemsElements.length > 0) {
38
+ const foundElement = displayedItemsElements.find(
39
+ element => element.value.toLowerCase().includes(value.toLowerCase())
40
+ );
41
+ if (foundElement) {
42
+ if (foundElement.disabled) {
43
+ foundElement.closest("li").focus();
44
+ } else {
45
+ foundElement.focus();
46
+ }
47
+ }
48
+ }
49
+ }
50
+
51
+ function handleComboKey(event, index) {
52
+ if (event.key === "ArrowDown") {
53
+ event.preventDefault();
54
+ event.stopPropagation();
55
+
56
+ if (displayedItems.length > 0 && index < displayedItems.length - 1) {
57
+ if (displayedItems[index + 1].disabled) {
58
+ displayedItemsElements[index + 1].closest("li").focus();
59
+ } else {
60
+ displayedItemsElements[index + 1].focus();
61
+ }
62
+ }
63
+ }
64
+
65
+ if (event.key === "ArrowUp") {
66
+ event.preventDefault();
67
+ event.stopPropagation();
68
+
69
+ if (displayedItems.length > 0 && index > 0) {
70
+ if (displayedItems[index - 1].disabled) {
71
+ displayedItemsElements[index - 1].closest("li").focus();
72
+ } else {
73
+ displayedItemsElements[index - 1].focus();
74
+ }
75
+ } else {
76
+ focusOnOuterElement();
77
+ }
78
+ }
79
+
80
+ if (event.key === "Enter") {
81
+ event.preventDefault();
82
+ event.stopPropagation();
83
+
84
+ if (displayedItems.length > 0 && !displayedItems[index].disabled) {
85
+ event.target.checked = !event.target.checked;
86
+ displayedItems[index].checked = event.target.checked;
87
+ }
88
+ }
89
+
90
+ Utils.sleep(5).then(() => {
91
+ if (canExit(event, index)) {
92
+ handleExit(event.key);
93
+ }
94
+ }).catch(console.error);
95
+ }
96
+
97
+ function handleKeyDown(event, index) {
98
+ if (event.key.match(/^\w$/i)) {
99
+ handlePrintableCharacter(event);
100
+ } else {
101
+ handleComboKey(event, index);
102
+ }
103
+ }
104
+
105
+ function handleLiKeyDown(event, index) {
106
+ if (event.target.tagName !== "INPUT") {
107
+ handleKeyDown(event, index);
108
+
109
+ if (event.key !== "Tab") {
110
+ event.preventDefault();
111
+ event.stopPropagation();
112
+ }
113
+ }
114
+ }
115
+
116
+ function handleLiClick(event, item) {
117
+ if (event.target.tagName !== "INPUT") {
118
+ event.preventDefault();
119
+ event.stopPropagation();
120
+
121
+ if (!item.disabled) {
122
+ item.checked = !item.checked;
123
+ }
124
+ }
125
+ }
126
+
127
+ function canExit(event, index) {
128
+ return event.key === "Escape" || (!event.shiftKey && event.key === "Tab" && index === displayedItems.length - 1);
129
+ }
130
+
131
+ function handleChange() {
132
+ selectionCallback();
133
+ }
134
+
135
+ function itemsHaveIds() {
136
+ let valid = true;
137
+ displayedItems.forEach(item => {
138
+ if (!item.id) {
139
+ valid = false;
140
+ }
141
+ });
142
+ return valid;
143
+ }
144
+ </script>
145
+
146
+ {#if displayedItems.length > 0 && itemsHaveIds()}
147
+ <ul>
148
+ {#each displayedItems as item, index (item.id)}
149
+ <!-- svelte-ignore a11y_no_noninteractive_tabindex -->
150
+ <!-- svelte-ignore a11y_no_noninteractive_element_interactions -->
151
+ <!-- Pour conserver la navigation d'un élément <select>, le focus doit pouvoir se faire sur les éléments
152
+ <li> dont le <Checkbox> interne est disabled.-->
153
+ <li
154
+ class={[
155
+ "qc-dropdown-list-multiple",
156
+ item.disabled ? "qc-disabled" : "qc-dropdown-list-active"
157
+ ]}
158
+ tabindex={item.disabled ? "0" : "-1"}
159
+ onkeydown={(e) => handleLiKeyDown(e, index)}
160
+ onclick={(e) => handleLiClick(e, item)}
161
+ >
162
+
163
+ <label
164
+ class="qc-choicefield-label"
165
+ compact
166
+ for={item.id + "-checkbox"}
167
+ >
168
+ <input
169
+ id={item.id + "-checkbox"}
170
+ type="checkbox"
171
+ class="qc-choicefield qc-compact"
172
+ value={item.value}
173
+ {name}
174
+ disabled={item.disabled}
175
+ bind:checked={item.checked}
176
+ bind:this={displayedItemsElements[index]}
177
+ onchange={handleChange}
178
+ onkeydown={(e) => handleKeyDown(e, index)}
179
+ />
180
+ <span>{item.label}</span>
181
+ </label>
182
+ </li>
183
+ {/each}
184
+ </ul>
185
+ {/if}
@@ -0,0 +1,19 @@
1
+ @use "qc-sdg-lib" as *;
2
+
3
+ .qc-dropdown-list-multiple {
4
+ margin: 0;
5
+
6
+ label {
7
+ margin: 0;
8
+ padding-left: token-value(spacer, xs);
9
+ padding-right: token-value(spacer, xs);
10
+ flex-grow: 1;
11
+ align-items: center;
12
+ }
13
+ .qc-choicefield {
14
+ margin-top: 0 !important;
15
+ &:focus {
16
+ outline: none;
17
+ }
18
+ }
19
+ }
@@ -0,0 +1,136 @@
1
+ <script>
2
+ import {Utils} from "../../../utils";
3
+
4
+ const selectedElementCLass = "qc-dropdown-list-single-selected";
5
+
6
+ let {
7
+ items,
8
+ displayedItems,
9
+ placeholder,
10
+ selectionCallback = () => {},
11
+ handleExit = () => {},
12
+ focusOnOuterElement = () => {},
13
+ handlePrintableCharacter = () => {}
14
+ } = $props();
15
+
16
+ let displayedItemsElements = $state(new Array(displayedItems.length));
17
+
18
+ export function focusOnFirstElement() {
19
+ if (displayedItemsElements && displayedItemsElements.length > 0) {
20
+ displayedItemsElements[0].focus();
21
+ }
22
+ }
23
+
24
+ export function focusOnLastElement() {
25
+ if (displayedItemsElements && displayedItemsElements.length > 0) {
26
+ displayedItemsElements[displayedItemsElements.length - 1].focus();
27
+ }
28
+ }
29
+
30
+ export function focusOnFirstMatchingElement(passedValue) {
31
+ if (displayedItemsElements && displayedItemsElements.length > 0) {
32
+ const foundElement = displayedItemsElements.find(
33
+ el => el.dataset.itemValue.toString() === passedValue.toString()
34
+ );
35
+ if (foundElement) {
36
+ foundElement.focus();
37
+ }
38
+ }
39
+ }
40
+
41
+ function handleSelection(event, item) {
42
+ event.preventDefault();
43
+
44
+ if (!item.disabled) {
45
+ items.forEach(item => item.checked = false);
46
+ items.find(option => option.value === item.value).checked = true;
47
+ selectionCallback();
48
+ }
49
+ }
50
+
51
+ function handleMouseUp(event, item) {
52
+ handleSelection(event, item);
53
+ }
54
+
55
+ function handleComboKey(event, index, item) {
56
+ if (event.key === "ArrowDown") {
57
+ event.preventDefault();
58
+ event.stopPropagation();
59
+
60
+ if (displayedItemsElements.length > 0 && index < displayedItemsElements.length - 1) {
61
+ displayedItemsElements[index + 1].focus();
62
+ }
63
+ }
64
+
65
+ if (event.key === "ArrowUp") {
66
+ event.preventDefault();
67
+ event.stopPropagation();
68
+
69
+ if (displayedItemsElements.length > 0 && index > 0) {
70
+ displayedItemsElements[index - 1].focus();
71
+ } else {
72
+ focusOnOuterElement();
73
+ }
74
+ }
75
+
76
+ if (event.key === "Enter" || event.key === " ") {
77
+ handleSelection(event, item);
78
+ }
79
+
80
+ Utils.sleep(5).then(() => {
81
+ if (canExit(event, index)) {
82
+ handleExit(event.key);
83
+ }
84
+ }).catch(console.error);
85
+ }
86
+
87
+ function handleKeyDown (event, index, item) {
88
+ if (event.key.match(/^\w$/i)) {
89
+ handlePrintableCharacter(event);
90
+ } else {
91
+ handleComboKey(event, index, item);
92
+ }
93
+ }
94
+
95
+ function canExit(event, index) {
96
+ return event.key === "Escape" || (!event.shiftKey && event.key === "Tab" && index === displayedItems.length - 1);
97
+ }
98
+
99
+ function itemsHaveIds() {
100
+ let valid = true;
101
+ displayedItems.forEach(item => {
102
+ if (!item.id) {
103
+ valid = false;
104
+ }
105
+ });
106
+ return valid;
107
+ }
108
+ </script>
109
+
110
+ {#if displayedItems.length > 0 && itemsHaveIds()}
111
+ <ul>
112
+ {#each displayedItems as item, index (item.id)}
113
+ <li
114
+ bind:this={displayedItemsElements[index]}
115
+ id={item.id}
116
+ class={[
117
+ "qc-dropdown-list-single",
118
+ item.disabled ? "qc-disabled" : "qc-dropdown-list-active",
119
+ item.checked ? selectedElementCLass : "",
120
+ ]}
121
+ data-item-value={item.value}
122
+ tabindex="0"
123
+ role="option"
124
+ aria-selected={!!item.checked}
125
+ onclick={(event) => handleMouseUp(event, item)}
126
+ onkeydown={(event) => handleKeyDown(event, index, item)}
127
+ >
128
+ {#if !item.value && !item.label}
129
+ <span class="qc-sr-only">{@html placeholder}</span>
130
+ {:else}
131
+ {@html item.label}
132
+ {/if}
133
+ </li>
134
+ {/each}
135
+ </ul>
136
+ {/if}
@@ -0,0 +1,11 @@
1
+ @use "../../../../scss/qc-sdg-lib" as *;
2
+
3
+ .qc-dropdown-list-single {
4
+ padding-left: token-value(spacer, xs);
5
+ padding-right: token-value(spacer, xs);
6
+ margin: 0;
7
+ }
8
+
9
+ li[aria-selected="true"] {
10
+ background-color: token-value(color, blue, pale) !important;
11
+ }
@@ -0,0 +1,67 @@
1
+ @use "../../../scss/qc-sdg-lib" as *;
2
+ @use "DropdownListItemsMultiple/dropdownListItemsMultiple";
3
+ @use "DropdownListItemsSingle/dropdownListItemsSingle";
4
+
5
+ $min-height: 40;
6
+
7
+ .qc-dropdown-list-items {
8
+ max-height: var(--dropdown-items-height);
9
+ overflow-y: auto;
10
+ overflow-x: hidden;
11
+
12
+ &::-webkit-scrollbar {
13
+ width: token-value(spacer, xs);
14
+ margin-left: token-value(spacer, xs);
15
+ margin-right: token-value(spacer, xs);
16
+ }
17
+
18
+ &::-webkit-scrollbar-track {
19
+ background: transparent;
20
+ }
21
+
22
+ &::-webkit-scrollbar-thumb {
23
+ background: token-value(color, blue, piv);
24
+ border-radius: rem(4);
25
+
26
+ border: none;
27
+ }
28
+
29
+ @supports not selector(::-webkit-scrollbar) {
30
+ scrollbar-color: token-value(color, blue, piv) transparent;
31
+ scrollbar-width: thin;
32
+ }
33
+
34
+ ul {
35
+ padding: 0;
36
+ margin: 0;
37
+ }
38
+
39
+ * {
40
+ overflow: hidden;
41
+ white-space: nowrap;
42
+ text-overflow: ellipsis;
43
+ }
44
+ }
45
+
46
+ .qc-dropdown-list-multiple, .qc-dropdown-list-single {
47
+ display: flex;
48
+ align-items: center;
49
+ height: rem($min-height);
50
+
51
+ &.qc-dropdown-list-active:hover {
52
+ background-color: token-value(color, grey, pale);
53
+ cursor: pointer;
54
+ }
55
+
56
+ &:focus, &:has(input[type=checkbox]:focus) {
57
+ outline: rem(2) solid token-value(color, blue, regular);
58
+ outline-offset: -(rem(2));
59
+ }
60
+ }
61
+
62
+ .qc-dropdown-list-no-options {
63
+ display: flex;
64
+ padding: token-value(spacer, xs);
65
+ color: token-value(color, grey, medium);
66
+ height: rem($min-height);
67
+ }
@@ -0,0 +1,158 @@
1
+ <svelte:options customElement="{{
2
+ tag: 'qc-select',
3
+ props: {
4
+ id: {attribute: 'id', type: 'String'},
5
+ label: {attribute: 'label', type: 'String', reflect: true},
6
+ width: {attribute: 'width', type: 'String'},
7
+ value: {attribute: 'value', type: 'String', reflect: true},
8
+ enableSearch: {attribute: 'enable-search', type: 'Boolean'},
9
+ required: {attribute: 'required', type: 'Boolean'},
10
+ disabled: {attribute: 'disabled', type: 'Boolean'},
11
+ invalid: {attribute: 'invalid', type: 'Boolean', reflect: true},
12
+ invalidText: {attribute: 'invalid-text', type: 'String'},
13
+ placeholder: {attribute: 'placeholder', type: 'String'},
14
+ searchPlaceholder: {attribute: 'search-placeholder', type: 'String'},
15
+ noOptionsMessage: {attribute: 'no-options-message', type: 'String'},
16
+ multiple: {attribute: 'multiple', type: 'Boolean'}
17
+ }
18
+ }}"/>
19
+
20
+ <script>
21
+ import {onDestroy, onMount} from "svelte";
22
+ import DropdownList from "./DropdownList.svelte";
23
+ import {Utils} from "../utils";
24
+
25
+ let {
26
+ invalid = $bindable(false),
27
+ value = $bindable([]),
28
+ multiple,
29
+ disabled,
30
+ required,
31
+ label,
32
+ placeholder,
33
+ width,
34
+ ...rest
35
+ } = $props();
36
+
37
+ const availableWidths = ["xs", "sm", "md", "lg", "xl"];
38
+
39
+ let selectElement = $state();
40
+ let items = $state();
41
+ let labelElement = $state();
42
+ let observer;
43
+ let instance = $state();
44
+ let errorElement = $state();
45
+ let parentRow = $derived($host().closest(".qc-formfield-row"));
46
+ let widthClass = $derived.by(() => {
47
+ if (availableWidths.includes(width)) {
48
+ return `qc-dropdown-list-root-${width}`;
49
+ }
50
+ return `qc-dropdown-list-root-md`;
51
+ });
52
+
53
+ onMount(() => {
54
+ selectElement = $host().querySelector("select");
55
+ labelElement = $host().querySelector("label");
56
+
57
+ if (labelElement) {
58
+ label = labelElement.innerHTML;
59
+ }
60
+ if (selectElement) {
61
+ multiple = selectElement.multiple;
62
+ disabled = selectElement.disabled;
63
+ }
64
+
65
+ setupItemsList();
66
+ setupObserver();
67
+ });
68
+
69
+ onDestroy(() => {
70
+ observer?.disconnect();
71
+ });
72
+
73
+ $effect(() => {
74
+ if (
75
+ selectElement
76
+ && selectElement.options
77
+ && selectElement.options.length > 0
78
+ && value
79
+ && value.length > 0
80
+ ) {
81
+ for (const option of selectElement.options) {
82
+ if (value.includes(option.value)) {
83
+ option.setAttribute('selected', '');
84
+ option.selected = true;
85
+ } else {
86
+ option.removeAttribute('selected');
87
+ option.selected = false;
88
+ }
89
+ }
90
+ }
91
+ });
92
+
93
+ $effect(() => {
94
+ if (parentRow && errorElement) {
95
+ parentRow.appendChild(errorElement);
96
+ }
97
+ });
98
+
99
+ $effect(() => {
100
+ if (widthClass) {
101
+ $host().classList.add("qc-dropdown-list-root");
102
+ $host().classList.add(widthClass);
103
+ }
104
+ });
105
+
106
+ function setupItemsList() {
107
+ const options = selectElement?.querySelectorAll("option");
108
+ if (options && options.length > 0) {
109
+ items = Array.from(options).map(option => ({
110
+ value: option.value,
111
+ label: option.label ?? option.innerHTML,
112
+ checked: option.selected,
113
+ disabled: option.disabled,
114
+ }));
115
+ } else {
116
+ items = [];
117
+ }
118
+ }
119
+
120
+ function setupObserver() {
121
+ if (selectElement) {
122
+ if (observer) {
123
+ return;
124
+ }
125
+ observer = new MutationObserver(setupItemsList);
126
+ observer.observe(selectElement, {
127
+ childList: true,
128
+ attributes: true,
129
+ attributeFilter: ["label", "value", "disabled", "selected"]
130
+ });
131
+ }
132
+ }
133
+
134
+
135
+ </script>
136
+
137
+ <div hidden>
138
+ <slot />
139
+ </div>
140
+
141
+ <DropdownList
142
+ {label}
143
+ ariaLabel={selectElement?.getAttribute("aria-label")}
144
+ {items}
145
+ {placeholder}
146
+ {width}
147
+ webComponentMode={true}
148
+ webComponentParentRow={parentRow}
149
+ bind:value
150
+ bind:errorElement
151
+ bind:invalid
152
+ bind:rootElement={instance}
153
+ {multiple}
154
+ {disabled}
155
+ {required}
156
+ {...rest}
157
+ />
158
+ <link rel='stylesheet' href='{Utils.cssPath}'>