adp-web-components 0.3.19 → 0.3.20

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 (346) hide show
  1. package/dist/cjs/{branch-slot-dropdown_15.cjs.entry.js → branch-date-dropdown_17.cjs.entry.js} +958 -68
  2. package/dist/cjs/dead-stock-lookup_3.cjs.entry.js +9 -9
  3. package/dist/cjs/flexible-container.cjs.entry.js +3 -3
  4. package/dist/cjs/form-checkbox.cjs.entry.js +2 -2
  5. package/dist/cjs/form-date-picker.cjs.entry.js +5 -5
  6. package/dist/cjs/form-input_7.cjs.entry.js +21 -19
  7. package/dist/cjs/form-switch.cjs.entry.js +2 -2
  8. package/dist/cjs/form-time-picker.cjs.entry.js +6 -6
  9. package/dist/cjs/{functions-DL7oNhTD.js → functions-BAUJUMt-.js} +44 -19
  10. package/dist/cjs/general-form.cjs.entry.js +6 -6
  11. package/dist/cjs/general-inquiry-form.cjs.entry.js +6 -6
  12. package/dist/cjs/{get-local-language-BuK1vyX4.js → get-local-language-DI_UK6D5.js} +1 -1
  13. package/dist/cjs/{get-mock-files-D0TNQtTV.js → get-mock-files-B1tNGb9m.js} +1 -1
  14. package/dist/cjs/information-table.cjs.entry.js +1 -1
  15. package/dist/cjs/loader.cjs.js +1 -1
  16. package/dist/cjs/loading-spinner.cjs.entry.js +2 -2
  17. package/dist/cjs/manufacturer-part-lookup.cjs.entry.js +3 -3
  18. package/dist/cjs/{mappers-BlH-TAo7.js → mappers-DnWgECCv.js} +54 -18
  19. package/dist/cjs/part-lookup.cjs.entry.js +2 -2
  20. package/dist/cjs/service-booking-form.cjs.entry.js +6 -6
  21. package/dist/cjs/shift-accordion.cjs.entry.js +2 -2
  22. package/dist/cjs/shift-checkbox.cjs.entry.js +2 -2
  23. package/dist/cjs/shift-components.cjs.js +1 -1
  24. package/dist/cjs/shift-slider.cjs.entry.js +2 -2
  25. package/dist/cjs/shift-switch.cjs.entry.js +2 -2
  26. package/dist/cjs/shift-tab-content.cjs.entry.js +2 -2
  27. package/dist/cjs/shift-tabs_2.cjs.entry.js +10 -10
  28. package/dist/cjs/ssc-lookup-form.cjs.entry.js +6 -6
  29. package/dist/cjs/test-drive-form.cjs.entry.js +6 -6
  30. package/dist/cjs/vehicle-accessories_8.cjs.entry.js +21 -21
  31. package/dist/cjs/vehicle-lookup.cjs.entry.js +3 -3
  32. package/dist/cjs/vehicle-quotation-form.cjs.entry.js +17 -18
  33. package/dist/collection/collection-manifest.json +2 -0
  34. package/dist/collection/components/components/empty.css +1 -1
  35. package/dist/collection/components/components/flexible-container.css +1 -1
  36. package/dist/collection/components/components/flexible-container.js +2 -2
  37. package/dist/collection/components/components/information-table.css +1 -1
  38. package/dist/collection/components/components/loading-spinner.css +1 -1
  39. package/dist/collection/components/components/loading-spinner.js +1 -1
  40. package/dist/collection/components/components/shift-accordion.css +1 -1
  41. package/dist/collection/components/components/shift-accordion.js +1 -1
  42. package/dist/collection/components/components/shift-checkbox.js +1 -1
  43. package/dist/collection/components/components/shift-portal.css +1 -1
  44. package/dist/collection/components/components/shift-select-dropdown.css +1 -1
  45. package/dist/collection/components/components/shift-select-dropdown.js +2 -2
  46. package/dist/collection/components/components/shift-select.css +1 -1
  47. package/dist/collection/components/components/shift-select.js +3 -3
  48. package/dist/collection/components/components/shift-slider.css +1 -1
  49. package/dist/collection/components/components/shift-slider.js +1 -1
  50. package/dist/collection/components/components/shift-switch.js +1 -1
  51. package/dist/collection/components/components/shift-tab-content.css +1 -1
  52. package/dist/collection/components/components/shift-tab-content.js +1 -1
  53. package/dist/collection/components/components/shift-tabs.css +1 -1
  54. package/dist/collection/components/components/shift-tabs.js +2 -2
  55. package/dist/collection/components/form-elements/branch-date-dropdown.css +1 -0
  56. package/dist/collection/components/form-elements/branch-date-dropdown.js +682 -0
  57. package/dist/collection/components/form-elements/branch-date-picker.css +1 -0
  58. package/dist/collection/components/form-elements/branch-date-picker.js +1197 -0
  59. package/dist/collection/components/form-elements/branch-slot-dropdown.css +1 -1
  60. package/dist/collection/components/form-elements/branch-slot-dropdown.js +11 -6
  61. package/dist/collection/components/form-elements/branch-slot-picker.css +1 -1
  62. package/dist/collection/components/form-elements/branch-slot-picker.js +166 -18
  63. package/dist/collection/components/form-elements/form-checkbox.js +1 -1
  64. package/dist/collection/components/form-elements/form-date-picker-legacy.js +4 -4
  65. package/dist/collection/components/form-elements/form-dialog.css +1 -1
  66. package/dist/collection/components/form-elements/form-dialog.js +1 -1
  67. package/dist/collection/components/form-elements/form-file.js +2 -2
  68. package/dist/collection/components/form-elements/form-input.js +6 -4
  69. package/dist/collection/components/form-elements/form-inputs.css +1 -1
  70. package/dist/collection/components/form-elements/form-phone-number.js +4 -2
  71. package/dist/collection/components/form-elements/form-picker-input.js +6 -4
  72. package/dist/collection/components/form-elements/form-shadow-input.js +1 -1
  73. package/dist/collection/components/form-elements/form-stepper-control.js +2 -2
  74. package/dist/collection/components/form-elements/form-stepper-submit.js +2 -2
  75. package/dist/collection/components/form-elements/form-stepper.js +1 -1
  76. package/dist/collection/components/form-elements/form-structure-error.js +1 -1
  77. package/dist/collection/components/form-elements/form-submit.js +2 -2
  78. package/dist/collection/components/form-elements/form-switch.js +1 -1
  79. package/dist/collection/components/form-elements/form-text-area.js +6 -4
  80. package/dist/collection/components/form-elements/form-time-picker-legacy.js +5 -5
  81. package/dist/collection/components/form-elements/form-vin-input.js +6 -4
  82. package/dist/collection/components/forms/defaults/mappers.js +54 -18
  83. package/dist/collection/components/forms/defaults/style.css +1 -1
  84. package/dist/collection/components/forms/general-form.js +2 -2
  85. package/dist/collection/components/forms/general-inquiry.js +2 -2
  86. package/dist/collection/components/forms/service-booking.js +2 -2
  87. package/dist/collection/components/forms/ssc-lookup.js +2 -2
  88. package/dist/collection/components/forms/test-drive.js +2 -2
  89. package/dist/collection/components/forms/vehicle-quotation/themes.css +1 -1
  90. package/dist/collection/components/forms/vehicle-quotation.js +15 -16
  91. package/dist/collection/components/part-lookup/dead-stock-lookup.css +1 -1
  92. package/dist/collection/components/part-lookup/dead-stock-lookup.js +2 -2
  93. package/dist/collection/components/part-lookup/distributor-lookup.css +1 -1
  94. package/dist/collection/components/part-lookup/distributor-lookup.js +2 -2
  95. package/dist/collection/components/part-lookup/manufacturer-lookup.css +1 -1
  96. package/dist/collection/components/part-lookup/manufacturer-part-lookup.css +1 -1
  97. package/dist/collection/components/part-lookup/manufacturer-part-lookup.js +1 -1
  98. package/dist/collection/components/part-lookup/part-lookup.css +1 -1
  99. package/dist/collection/components/vehicle-lookup/vehicle-accessories.css +1 -1
  100. package/dist/collection/components/vehicle-lookup/vehicle-accessories.js +2 -2
  101. package/dist/collection/components/vehicle-lookup/vehicle-claimable-items.css +1 -1
  102. package/dist/collection/components/vehicle-lookup/vehicle-claimable-items.js +5 -5
  103. package/dist/collection/components/vehicle-lookup/vehicle-item-claim-form.css +1 -1
  104. package/dist/collection/components/vehicle-lookup/vehicle-item-claim-form.js +6 -6
  105. package/dist/collection/components/vehicle-lookup/vehicle-lookup.css +1 -1
  106. package/dist/collection/components/vehicle-lookup/vehicle-paint-thickness.css +1 -1
  107. package/dist/collection/components/vehicle-lookup/vehicle-sale-information.css +1 -1
  108. package/dist/collection/components/vehicle-lookup/vehicle-sale-information.js +2 -2
  109. package/dist/collection/components/vehicle-lookup/vehicle-service-history.css +1 -1
  110. package/dist/collection/components/vehicle-lookup/vehicle-service-history.js +1 -1
  111. package/dist/collection/components/vehicle-lookup/vehicle-specification.css +1 -1
  112. package/dist/collection/components/vehicle-lookup/vehicle-specification.js +1 -1
  113. package/dist/collection/components/vehicle-lookup/vehicle-warranty-details.css +1 -1
  114. package/dist/collection/components/vehicle-lookup/vehicle-warranty-timeline.css +1 -1
  115. package/dist/collection/components/vehicle-lookup/vehicle-warranty-timeline.js +1 -1
  116. package/dist/collection/components/vin-extractor/vin-extractor.css +1 -1
  117. package/dist/collection/components/vin-extractor/vin-extractor.js +1 -1
  118. package/dist/collection/features/form-hook/functions.js +42 -18
  119. package/dist/collection/global/lib/slot-day-rules.js +65 -0
  120. package/dist/collection/templates/assets/favicon.svg +17 -0
  121. package/dist/collection/templates/forms/docs-content/params.js +1199 -0
  122. package/dist/collection/templates/forms/docs-content/structure.js +1153 -0
  123. package/dist/collection/templates/forms/docs-content/theming.js +1240 -0
  124. package/dist/collection/templates/harness.js +595 -84
  125. package/dist/collection/templates/highlight.js +194 -0
  126. package/dist/collection/templates/nav.js +320 -0
  127. package/dist/collection/templates/site-header.js +642 -0
  128. package/dist/collection/templates/site-locales.js +771 -0
  129. package/dist/components/branch-date-dropdown.d.ts +11 -0
  130. package/dist/components/branch-date-dropdown.js +5 -0
  131. package/dist/components/branch-date-picker.d.ts +11 -0
  132. package/dist/components/branch-date-picker.js +5 -0
  133. package/dist/components/branch-slot-dropdown.js +1 -1
  134. package/dist/components/branch-slot-picker.js +1 -1
  135. package/dist/components/dead-stock-lookup.js +1 -1
  136. package/dist/components/distributor-lookup.js +1 -1
  137. package/dist/components/flexible-container.js +1 -1
  138. package/dist/components/form-checkbox.js +1 -1
  139. package/dist/components/form-date-picker.js +1 -1
  140. package/dist/components/form-dialog.js +1 -1
  141. package/dist/components/form-file.js +1 -1
  142. package/dist/components/form-input-preview.js +1 -1
  143. package/dist/components/form-input.js +1 -1
  144. package/dist/components/form-phone-number.js +1 -1
  145. package/dist/components/form-picker-input.js +1 -1
  146. package/dist/components/form-select.js +1 -1
  147. package/dist/components/form-shadow-input.js +1 -1
  148. package/dist/components/form-stepper-control.js +1 -1
  149. package/dist/components/form-stepper-submit.js +1 -1
  150. package/dist/components/form-stepper.js +1 -1
  151. package/dist/components/form-structure-error.js +1 -1
  152. package/dist/components/form-structure.js +1 -1
  153. package/dist/components/form-submit.js +1 -1
  154. package/dist/components/form-switch.js +1 -1
  155. package/dist/components/form-text-area.js +1 -1
  156. package/dist/components/form-time-picker.js +1 -1
  157. package/dist/components/form-vin-input.js +1 -1
  158. package/dist/components/general-form.js +1 -1
  159. package/dist/components/general-inquiry-form.js +1 -1
  160. package/dist/components/information-table.js +1 -1
  161. package/dist/components/loading-spinner.js +1 -1
  162. package/dist/components/manufacturer-lookup.js +1 -1
  163. package/dist/components/manufacturer-part-lookup.js +1 -1
  164. package/dist/components/p--lk4OUJg.js +5 -0
  165. package/dist/components/{p-DbnN292R.js → p-38ox9qxm.js} +1 -1
  166. package/dist/components/p-5OD_mwiD.js +5 -0
  167. package/dist/components/{p-l2FHTMzv.js → p-68bjv9gT.js} +1 -1
  168. package/dist/components/p-B0_5_VvS.js +5 -0
  169. package/dist/components/p-B1xVBTqj.js +5 -0
  170. package/dist/components/{p-B7G2HjX0.js → p-B2bD-55K.js} +1 -1
  171. package/dist/components/{p-BKzXBxxc.js → p-BI5NL1Rh.js} +1 -1
  172. package/dist/components/{p-CL5G_ZDE.js → p-BPXRokES.js} +1 -1
  173. package/dist/components/{p-D7Sj02XY.js → p-BULuujHY.js} +1 -1
  174. package/dist/components/{p-CC16uGpN.js → p-BWlX-Nz-.js} +1 -1
  175. package/dist/components/p-Bc5HIbcj.js +5 -0
  176. package/dist/components/p-BcWJAP8j.js +5 -0
  177. package/dist/components/p-BpB_86n0.js +5 -0
  178. package/dist/components/p-BpHkd1L9.js +5 -0
  179. package/dist/components/{p-Qh1y1RV2.js → p-BsnGFZeT.js} +1 -1
  180. package/dist/components/{p-Dd_Xnn2b.js → p-BvLVCp-j.js} +1 -1
  181. package/dist/components/p-C3KLOUbk.js +5 -0
  182. package/dist/components/{p-BaZAgTxG.js → p-CJtTHErI.js} +1 -1
  183. package/dist/components/{p-R_rAJ4hF.js → p-CMAmzdM7.js} +1 -1
  184. package/dist/components/p-CVpbr1tR.js +5 -0
  185. package/dist/components/{p-6RmAcc2q.js → p-CXbi5iPZ.js} +1 -1
  186. package/dist/components/p-C_1_eN4N.js +5 -0
  187. package/dist/components/{p-B9xLzbPr.js → p-Ce2mazYo.js} +1 -1
  188. package/dist/components/p-Cg6Prz81.js +5 -0
  189. package/dist/components/{p-CwbJMZVZ.js → p-Cpjvk1pk.js} +1 -1
  190. package/dist/components/p-CqJiXtPb.js +5 -0
  191. package/dist/components/p-CrPyvAdX.js +5 -0
  192. package/dist/components/{p-C6U9Fs9H.js → p-CsU_c7eX.js} +1 -1
  193. package/dist/components/{p-LkNhSGDO.js → p-D42YuMNZ.js} +1 -1
  194. package/dist/components/{p-CIPh05sT.js → p-DCpRGVqe.js} +1 -1
  195. package/dist/components/{p-DcMgXNpe.js → p-DCsMDWbS.js} +1 -1
  196. package/dist/components/{p-B8hl68AM.js → p-DQ0uTCi2.js} +1 -1
  197. package/dist/components/p-DTmI_Yx0.js +5 -0
  198. package/dist/components/p-DnspXuVN.js +5 -0
  199. package/dist/components/p-DqSdjh2n.js +5 -0
  200. package/dist/components/p-Dv2j7fhS.js +5 -0
  201. package/dist/components/{p-C8S2P4sw.js → p-K-OF4DG-.js} +1 -1
  202. package/dist/components/p-KSvRVGk-.js +5 -0
  203. package/dist/components/p-KbiYvxzP.js +5 -0
  204. package/dist/components/{p-B2w49gNR.js → p-OY4Ixaeq.js} +1 -1
  205. package/dist/components/{p-Dsk1SNut.js → p-SIS25ChD.js} +1 -1
  206. package/dist/components/p-Wgb4y0H3.js +5 -0
  207. package/dist/components/p-X3AzJ0KD.js +5 -0
  208. package/dist/components/{p-Cm94OAx9.js → p-bCeQwUKM.js} +1 -1
  209. package/dist/components/p-d3ZIPeEC.js +5 -0
  210. package/dist/components/{p-DpXLfNHS.js → p-ikaUQvOO.js} +1 -1
  211. package/dist/components/p-mbVTvSJF.js +5 -0
  212. package/dist/components/{p-BbQAkWw4.js → p-rQ3Z9EnS.js} +1 -1
  213. package/dist/components/{p-BdPZ7u2w.js → p-uYkn8a0m.js} +1 -1
  214. package/dist/components/part-lookup.js +1 -1
  215. package/dist/components/service-booking-form.js +1 -1
  216. package/dist/components/shift-accordion.js +1 -1
  217. package/dist/components/shift-checkbox.js +1 -1
  218. package/dist/components/shift-portal.js +1 -1
  219. package/dist/components/shift-select-dropdown.js +1 -1
  220. package/dist/components/shift-select.js +1 -1
  221. package/dist/components/shift-slider.js +1 -1
  222. package/dist/components/shift-switch.js +1 -1
  223. package/dist/components/shift-tab-content.js +1 -1
  224. package/dist/components/shift-tabs.js +1 -1
  225. package/dist/components/ssc-lookup-form.js +1 -1
  226. package/dist/components/test-drive-form.js +1 -1
  227. package/dist/components/vehicle-accessories.js +1 -1
  228. package/dist/components/vehicle-claimable-items.js +1 -1
  229. package/dist/components/vehicle-item-claim-form.js +1 -1
  230. package/dist/components/vehicle-lookup.js +1 -1
  231. package/dist/components/vehicle-paint-thickness.js +1 -1
  232. package/dist/components/vehicle-quotation-form.js +1 -1
  233. package/dist/components/vehicle-sale-information.js +1 -1
  234. package/dist/components/vehicle-service-history.js +1 -1
  235. package/dist/components/vehicle-specification.js +1 -1
  236. package/dist/components/vehicle-warranty-details.js +1 -1
  237. package/dist/components/vehicle-warranty-timeline.js +1 -1
  238. package/dist/components/vin-extractor.js +1 -1
  239. package/dist/esm/{branch-slot-dropdown_15.entry.js → branch-date-dropdown_17.entry.js} +957 -69
  240. package/dist/esm/dead-stock-lookup_3.entry.js +9 -9
  241. package/dist/esm/flexible-container.entry.js +3 -3
  242. package/dist/esm/form-checkbox.entry.js +2 -2
  243. package/dist/esm/form-date-picker.entry.js +5 -5
  244. package/dist/esm/form-input_7.entry.js +21 -19
  245. package/dist/esm/form-switch.entry.js +2 -2
  246. package/dist/esm/form-time-picker.entry.js +6 -6
  247. package/dist/esm/{functions-Ccrile_u.js → functions-DSwc1YVL.js} +44 -20
  248. package/dist/esm/general-form.entry.js +6 -6
  249. package/dist/esm/general-inquiry-form.entry.js +6 -6
  250. package/dist/esm/{get-local-language-oNw84Rsz.js → get-local-language-DdSAPSCV.js} +1 -1
  251. package/dist/esm/{get-mock-files-C26lznN1.js → get-mock-files-D4naDetb.js} +1 -1
  252. package/dist/esm/information-table.entry.js +1 -1
  253. package/dist/esm/loader.js +1 -1
  254. package/dist/esm/loading-spinner.entry.js +2 -2
  255. package/dist/esm/manufacturer-part-lookup.entry.js +3 -3
  256. package/dist/esm/{mappers-9IKbvPiR.js → mappers-CZs2R7k6.js} +54 -18
  257. package/dist/esm/part-lookup.entry.js +2 -2
  258. package/dist/esm/service-booking-form.entry.js +6 -6
  259. package/dist/esm/shift-accordion.entry.js +2 -2
  260. package/dist/esm/shift-checkbox.entry.js +2 -2
  261. package/dist/esm/shift-components.js +1 -1
  262. package/dist/esm/shift-slider.entry.js +2 -2
  263. package/dist/esm/shift-switch.entry.js +2 -2
  264. package/dist/esm/shift-tab-content.entry.js +2 -2
  265. package/dist/esm/shift-tabs_2.entry.js +10 -10
  266. package/dist/esm/ssc-lookup-form.entry.js +6 -6
  267. package/dist/esm/test-drive-form.entry.js +6 -6
  268. package/dist/esm/vehicle-accessories_8.entry.js +21 -21
  269. package/dist/esm/vehicle-lookup.entry.js +3 -3
  270. package/dist/esm/vehicle-quotation-form.entry.js +17 -18
  271. package/dist/integration-manifest.json +1 -1
  272. package/dist/shift-components/{p-9b13a82b.entry.js → p-0b576888.entry.js} +1 -1
  273. package/dist/shift-components/p-11ffa908.entry.js +5 -0
  274. package/dist/shift-components/{p-f2a546db.entry.js → p-152057de.entry.js} +1 -1
  275. package/dist/shift-components/p-198333fa.entry.js +5 -0
  276. package/dist/shift-components/{p-d58404bd.entry.js → p-247ac2db.entry.js} +1 -1
  277. package/dist/shift-components/{p-d59276b6.entry.js → p-295e445f.entry.js} +1 -1
  278. package/dist/shift-components/p-431522f2.entry.js +5 -0
  279. package/dist/shift-components/{p-c9ba7fd5.entry.js → p-49dc6d73.entry.js} +1 -1
  280. package/dist/shift-components/{p-eb265a3e.entry.js → p-4b6f801a.entry.js} +1 -1
  281. package/dist/shift-components/{p-0da97a29.entry.js → p-4cdeab63.entry.js} +1 -1
  282. package/dist/shift-components/{p-31718ec2.entry.js → p-52530fba.entry.js} +1 -1
  283. package/dist/shift-components/p-5ad4d072.entry.js +5 -0
  284. package/dist/shift-components/{p-3aad8840.entry.js → p-5e8e5ed7.entry.js} +1 -1
  285. package/dist/shift-components/{p-09a0fd99.entry.js → p-68e41217.entry.js} +1 -1
  286. package/dist/shift-components/{p-a15fdf1e.entry.js → p-76b0ea8c.entry.js} +1 -1
  287. package/dist/shift-components/{p-68722c7b.entry.js → p-85d43a41.entry.js} +1 -1
  288. package/dist/shift-components/p-B9INqdFT.js +5 -0
  289. package/dist/shift-components/{p-urLq-GEs.js → p-D2Ofzg_i.js} +1 -1
  290. package/dist/shift-components/p-DDtDRGFL.js +5 -0
  291. package/dist/shift-components/{p-BugYpTL6.js → p-OfPuHUYc.js} +1 -1
  292. package/dist/shift-components/p-b44b2c00.entry.js +5 -0
  293. package/dist/shift-components/{p-1355934b.entry.js → p-b4544d10.entry.js} +1 -1
  294. package/dist/shift-components/{p-e90c354a.entry.js → p-bfe0661c.entry.js} +1 -1
  295. package/dist/shift-components/{p-138af7f3.entry.js → p-c7fc8d5f.entry.js} +1 -1
  296. package/dist/shift-components/{p-30e84a3b.entry.js → p-ca0683e9.entry.js} +1 -1
  297. package/dist/shift-components/{p-53cd54e8.entry.js → p-cbdc1c2e.entry.js} +1 -1
  298. package/dist/shift-components/p-d3bbba07.entry.js +5 -0
  299. package/dist/shift-components/{p-63713eae.entry.js → p-df0c7ac1.entry.js} +1 -1
  300. package/dist/shift-components/p-f4679148.entry.js +5 -0
  301. package/dist/shift-components/{p-729d8d4b.entry.js → p-feb443ec.entry.js} +1 -1
  302. package/dist/shift-components/shift-components.esm.js +1 -1
  303. package/dist/stencil-docs.json +1677 -12
  304. package/dist/templates/production-host/vehicle-service-history.html +14 -0
  305. package/dist/types/components/form-elements/branch-date-dropdown.d.ts +74 -0
  306. package/dist/types/components/form-elements/branch-date-picker.d.ts +174 -0
  307. package/dist/types/components/form-elements/branch-slot-dropdown.d.ts +6 -0
  308. package/dist/types/components/form-elements/branch-slot-picker.d.ts +27 -0
  309. package/dist/types/components/forms/defaults/mappers.d.ts +15 -9
  310. package/dist/types/components.d.ts +533 -6
  311. package/dist/types/features/form-hook/functions.d.ts +14 -0
  312. package/dist/types/global/lib/slot-day-rules.d.ts +25 -0
  313. package/dist/types/locales/vehicleLookup/serviceHistory/type.d.ts +2 -2
  314. package/dist/types/locales/vehicleLookup/warrantyTimeline/type.d.ts +4 -4
  315. package/dist/types/locales/vehicleLookup/wrapper-type.d.ts +2 -2
  316. package/package.json +6 -1
  317. package/dist/components/p-1fzw9lBq.js +0 -5
  318. package/dist/components/p-7Gq_FyNj.js +0 -5
  319. package/dist/components/p-8jIkK-Kb.js +0 -5
  320. package/dist/components/p-BUepGDZV.js +0 -5
  321. package/dist/components/p-B__72-PA.js +0 -5
  322. package/dist/components/p-Bb2xDuqh.js +0 -5
  323. package/dist/components/p-Bj3cvdzl.js +0 -5
  324. package/dist/components/p-BvMcY9Sk.js +0 -5
  325. package/dist/components/p-C-yTwaAA.js +0 -5
  326. package/dist/components/p-C8B9jarP.js +0 -5
  327. package/dist/components/p-CCounVqq.js +0 -5
  328. package/dist/components/p-CKwgX_v0.js +0 -5
  329. package/dist/components/p-CPBmhspv.js +0 -5
  330. package/dist/components/p-ClT5CzCZ.js +0 -5
  331. package/dist/components/p-DWjIts4C.js +0 -5
  332. package/dist/components/p-DeipsN8N.js +0 -5
  333. package/dist/components/p-DkagL-e-.js +0 -5
  334. package/dist/components/p-DtZM3yHS.js +0 -5
  335. package/dist/components/p-G7teNuSi.js +0 -5
  336. package/dist/components/p-_apNp6J3.js +0 -5
  337. package/dist/shift-components/p-12e295ba.entry.js +0 -5
  338. package/dist/shift-components/p-323ffb6e.entry.js +0 -5
  339. package/dist/shift-components/p-327fddd8.entry.js +0 -5
  340. package/dist/shift-components/p-34e9053b.entry.js +0 -5
  341. package/dist/shift-components/p-8374f629.entry.js +0 -5
  342. package/dist/shift-components/p-awXOnuq1.js +0 -5
  343. package/dist/shift-components/p-c25a6c0d.entry.js +0 -5
  344. package/dist/shift-components/p-dacdff2a.entry.js +0 -5
  345. package/dist/shift-components/p-hABirfUj.js +0 -5
  346. /package/dist/collection/templates/{vehicle-lookup → prototypes}/prototype-assets/extended-warranty/adp-logo.svg +0 -0
@@ -1,26 +1,190 @@
1
1
  /**
2
2
  * adp-web-components — dev harness controls (Alpine).
3
3
  *
4
- * Provides the `harness()` Alpine data factory and stamps the standard rail
5
- * markup into any `[data-harness-rail]` element, so a page describes what it is
6
- * testing instead of re-implementing the same six controls:
4
+ * Provides the `harness()` Alpine data factory and stamps the shared chrome into
5
+ * the placeholder elements below, so a page describes what it is testing instead
6
+ * of re-implementing navigation and the same six controls:
7
7
  *
8
- * <aside class="card border-base-300 bg-base-100 flex flex-col gap-4 border border-dashed p-4"
9
- * data-harness-rail
10
- * x-data="harness({ subject: '#subject', mocks: 'vehicle-lookup' })"></aside>
8
+ * <div data-harness-nav x-cloak></div>
11
9
  *
12
- * A page that needs a different rail just writes its own markup against the same
13
- * state — every method below is public.
10
+ * <section x-data="harness({ subject: '#subject', mocks: 'vehicle-lookup' })">
11
+ * <div data-harness-bar x-cloak></div>
12
+ * <div class="frame">…the component…</div>
13
+ * <div data-harness-rail x-cloak></div>
14
+ * </section>
15
+ *
16
+ * There are three stamped pieces:
17
+ *
18
+ * [data-harness-nav] The sticky bar at the top of the page: one dropdown per
19
+ * area, every page in it, read from catalog.json. It sits
20
+ * outside the harness scope and carries its own x-data.
21
+ *
22
+ * …and the controls, split by how often you touch them:
23
+ *
24
+ * [data-harness-bar] Mode and Fixtures, inline above the component. Reached
25
+ * in one click, because that is every interaction.
26
+ * [data-harness-rail] Language, theme, platform width and the event log, in a
27
+ * drawer behind a tab on the right edge (a button on a
28
+ * phone). Set once, then forgotten.
29
+ *
30
+ * The rail used to be a 300px aside, which cost the component under test a third
31
+ * of the page on every demo. Its stamped markup is all `position: fixed`, so the
32
+ * placeholder div can go anywhere inside the harness scope.
33
+ *
34
+ * `x-data` goes on a wrapper around BOTH the frame and the rail, not on the rail
35
+ * itself — that way a page-level control (an external submit button, a tab strip
36
+ * driving `activeElement`) binds to the same state the rail does.
37
+ *
38
+ * A page that needs a different rail writes its own markup against the same
39
+ * state — every method below is public. A page script with no Alpine scope at
40
+ * all can still reach the log:
41
+ *
42
+ * window.dispatchEvent(new CustomEvent('harness:log', { detail: { label: 'GET', detail: url } }));
14
43
  *
15
44
  * Control order is fixed on purpose (R5), and the language control flips page
16
45
  * direction because half of the supported set is RTL (R6). See
17
46
  * .shift/repos/adp/web-components/templates-design-language.md.
18
47
  */
19
48
 
49
+ /*
50
+ * Every path this file emits or compares is resolved against the directory this
51
+ * module was loaded from, never against the server root. Root-absolute paths
52
+ * only work when the site IS the server root, which is true for the Stencil dev
53
+ * server and false for VS Code Live Server, a subpath mount, or a preview
54
+ * deployment — all of which then serve the page but lose the whole navigation.
55
+ *
56
+ * harness.js is one shared file loaded from pages three directories deep, so a
57
+ * build-time depth-relative rewrite cannot fix this the way it fixes the asset
58
+ * tags; the fix has to be here, where `import.meta.url` knows the real depth.
59
+ */
60
+ const SITE_ROOT = new URL('../', import.meta.url);
61
+
62
+ /** A catalog path (`/templates/…`) as a URL path valid from wherever this page sits. */
63
+ const site = value => new URL(String(value).replace(/^\//, ''), SITE_ROOT).pathname;
64
+
65
+ /** Mirrors a component's loading flag onto the harness, so page controls can disable. */
66
+ function track(isLoading) {
67
+ this.loading = isLoading;
68
+
69
+ return [isLoading ? 'loading' : 'idle', ''];
70
+ }
71
+
72
+ /**
73
+ * Same idea for the error message: held on the harness so a page can render it
74
+ * next to its own input. Components clear the error by reporting an empty one,
75
+ * which is worth no log line.
76
+ */
77
+ function fail(message) {
78
+ this.error = message ? String(message) : '';
79
+
80
+ return this.error ? ['error', this.error] : null;
81
+ }
82
+
83
+ /**
84
+ * The four component shapes these demos drive. A profile is only a bundle of
85
+ * defaults — every field it sets can still be overridden per page.
86
+ *
87
+ * `events` maps a component callback property to a log line. Handlers run with
88
+ * the harness as `this`, and one that returns nothing logs nothing, which is how
89
+ * a callback can be used purely for its side effect.
90
+ */
91
+ const PROFILES = {
92
+ // vehicle-lookup family: a VIN goes in, one response comes back.
93
+ lookup: {
94
+ apply: (subject, data) => subject.setMockData(data),
95
+ select: (subject, key) => subject.fetchVin(key),
96
+ endpoint: subject => subject.baseUrl,
97
+ events: {
98
+ loadingStateChange: track,
99
+ errorCallback: fail,
100
+ loadedResponse: response => ['loaded', summarise(response)],
101
+ },
102
+ },
103
+
104
+ // part-lookup family: a part number goes in, and the component loads its own
105
+ // mock file when `isDev` flips rather than being handed one.
106
+ part: {
107
+ apply: null,
108
+ select: (subject, key) => subject.fetchData(key),
109
+ endpoint: subject => subject.endpoint?.url,
110
+ events: {
111
+ loadingStateChange: track,
112
+ errorCallback: fail,
113
+ loadedResponse: response => ['loaded', summarise(response)],
114
+ loadedMockDatas(data) {
115
+ const keys = Object.keys(data ?? {});
116
+
117
+ this.setFixtures(keys, data ?? {});
118
+
119
+ return ['mocks', `${keys.length} part ${keys.length === 1 ? 'number' : 'numbers'}`];
120
+ },
121
+ },
122
+ },
123
+
124
+ // forms: no fixture list — the structure JSON is the input, and what matters
125
+ // is the submit lifecycle.
126
+ form: {
127
+ apply: null,
128
+ select: null,
129
+ endpoint: subject => subject.structureUrl || subject.getAttribute('structure-url'),
130
+ events: {
131
+ formReadyCallback() {
132
+ this.ready = true;
133
+
134
+ return ['ready', 'structure loaded'];
135
+ },
136
+ loadingChanges(loading) {
137
+ this.loading = loading;
138
+
139
+ return [loading ? 'submitting' : 'idle', ''];
140
+ },
141
+ successCallback: data => ['success', summarise(data)],
142
+ errorCallback(error, message) {
143
+ this.error = String(message || error || '');
144
+
145
+ return ['error', this.error];
146
+ },
147
+ },
148
+ },
149
+
150
+ // vehicle-lookup: the shell that holds the eight single-vehicle components and
151
+ // shows one at a time. It reports its own state rather than the children's.
152
+ composite: {
153
+ apply: null,
154
+ endpoint: subject => subject.baseUrl,
155
+ // In development, push the fixture into every tab at once instead of only the
156
+ // active one, which is what `fetchVin` does — otherwise switching tabs shows
157
+ // whatever the previous search left behind. Empty and Error have no fixture,
158
+ // so they go the normal route and let each child render its own state.
159
+ select: (subject, key, harness) => {
160
+ const mock = harness.mode === 'dev' && harness.data?.[key];
161
+
162
+ return mock ? subject.handleLoadData(mock, null) : subject.fetchVin(key, { headers: 'headers-value' });
163
+ },
164
+ events: {
165
+ loadingStateChanged: track,
166
+ errorStateListener: fail,
167
+ dynamicClaimActivate: information => ['claim activate', information?.vin ?? '(no vin)'],
168
+ },
169
+ },
170
+ };
171
+
20
172
  const DEFAULTS = {
21
173
  subject: '#subject',
174
+ profile: 'lookup',
22
175
  mocks: null,
23
176
  labels: {},
177
+ // Fixture keys to offer in production mode, where there is no mock file to
178
+ // generate them from. Development mode always uses the generated list (R7).
179
+ samples: [],
180
+ // Fixture to run as soon as the subject is ready, so a page can deep-link a
181
+ // scenario (`?vin=…`) instead of asking whoever opened the link to click.
182
+ start: null,
183
+ // Which fixtures are worth offering on THIS page. One mock file feeds eight
184
+ // components and most VINs carry data for only some of them, so a page says
185
+ // what its component actually needs — `has: vehicle => vehicle.accessories?.length`
186
+ // — and the rest are counted out rather than sitting there rendering nothing.
187
+ has: null,
24
188
  languages: ['en', 'ku', 'ar', 'ru'],
25
189
  rtl: ['ar', 'ku'],
26
190
  platforms: [
@@ -29,16 +193,33 @@ const DEFAULTS = {
29
193
  { label: '768', value: '768px' },
30
194
  { label: 'Full', value: '100%' },
31
195
  ],
196
+ language: true,
32
197
  theme: true,
33
198
  mode: true,
34
199
  platform: true,
35
200
  log: true,
36
- apply: (subject, data) => subject.setMockData(data),
37
- select: (subject, key) => subject.fetchVin(key),
201
+ fixtures: null,
202
+ events: null,
203
+ // Runs once the subject has upgraded — the place for object-valued props that
204
+ // cannot be written as an attribute, such as part-lookup's `endpoint`.
205
+ setup: null,
206
+ // `undefined` means "take the profile's"; `null` means "this page has none".
207
+ apply: undefined,
208
+ select: undefined,
209
+ endpoint: undefined,
38
210
  };
39
211
 
40
212
  window.harness = function harness(options = {}) {
41
213
  const config = { ...DEFAULTS, ...options };
214
+ const profile = PROFILES[config.profile] ?? PROFILES.lookup;
215
+
216
+ const apply = config.apply === undefined ? profile.apply : config.apply;
217
+ const select = config.select === undefined ? profile.select : config.select;
218
+ const endpoint = config.endpoint === undefined ? profile.endpoint : config.endpoint;
219
+ // `false` wires nothing: a page demonstrating the Blazor bridge needs those
220
+ // same callback props left as the attribute strings the component dispatches
221
+ // through the .NET ref, and it feeds the log with `harness:log` instead.
222
+ const events = config.events === false ? {} : { ...profile.events, ...config.events };
42
223
 
43
224
  return {
44
225
  config,
@@ -47,11 +228,16 @@ window.harness = function harness(options = {}) {
47
228
  languages: config.languages,
48
229
  platforms: config.platforms,
49
230
  show: {
231
+ language: config.language,
50
232
  theme: config.theme,
51
233
  mode: config.mode,
52
234
  platform: config.platform,
53
235
  log: config.log,
54
- fixtures: Boolean(config.mocks),
236
+ fixtures: (config.fixtures ?? Boolean(config.mocks || config.samples.length)) && Boolean(select),
237
+ // The bar only earns its space when it has something in it.
238
+ get bar() {
239
+ return this.mode || this.fixtures;
240
+ },
55
241
  },
56
242
 
57
243
  language: config.languages[0],
@@ -59,16 +245,42 @@ window.harness = function harness(options = {}) {
59
245
  // Development is the default: it is the only mode that works without a local
60
246
  // API running, which is how these pages are opened most of the time.
61
247
  mode: 'dev',
248
+ // The rail is a drawer, not a column: it would otherwise take a third of the
249
+ // width away from the thing under test on every page.
250
+ open: false,
62
251
  width: '100%',
63
- fixtures: [],
252
+ loading: false,
253
+ // Last error the subject reported, so a page can show it beside its own input.
254
+ error: '',
255
+ // The loaded mock set, for a page whose `select` needs the fixture itself and
256
+ // not just its key.
257
+ data: null,
258
+ keys: [],
259
+ // How many fixtures `has` filtered out. Shown, never silently dropped.
260
+ hidden: 0,
64
261
  fixture: null,
262
+ // Forms flip this from formReadyCallback; an external submit button waits on it.
263
+ ready: false,
65
264
  lines: [],
66
265
 
67
266
  get dir() {
68
267
  return config.rtl.includes(this.language) ? 'rtl' : 'ltr';
69
268
  },
70
269
 
270
+ /** Empty and Error are always offered; the rest is generated, never listed (R7). */
271
+ get fixtures() {
272
+ const keys = this.mode === 'dev' ? this.keys : config.samples;
273
+
274
+ return [{ value: '', label: 'Empty' }, { value: 'error', label: 'Error' }, ...keys.map(key => ({ value: key, label: key, note: config.labels[key] }))];
275
+ },
276
+
71
277
  async init() {
278
+ // Any script on the page can write to the log without an Alpine scope.
279
+ window.addEventListener('harness:log', event => this.write(event.detail?.label, event.detail?.detail));
280
+
281
+ // A gallery page drives several elements itself and has no single subject.
282
+ if (config.subject === false) return;
283
+
72
284
  this.subject = document.querySelector(config.subject);
73
285
 
74
286
  if (!this.subject) return this.write('harness', `no element matches ${config.subject}`);
@@ -78,11 +290,17 @@ window.harness = function harness(options = {}) {
78
290
  await customElements.whenDefined(this.subject.localName);
79
291
  await this.subject.componentOnReady?.();
80
292
 
81
- this.setLanguage(this.subject.language || this.language);
293
+ await config.setup?.(this.subject, this);
294
+
295
+ if (config.language) this.setLanguage(this.subject.language || this.language);
296
+
297
+ // Before isDev, not after: flipping it makes some components load their own
298
+ // mock file and call straight back, so the listeners have to be in place.
299
+ this.observe();
82
300
  this.subject.isDev = true;
83
301
 
84
- if (config.log) this.observe();
85
302
  if (config.mocks) await this.loadFixtures();
303
+ if (config.start) this.run(config.start);
86
304
  },
87
305
 
88
306
  /* ---------- controls ---------- */
@@ -94,9 +312,27 @@ window.harness = function harness(options = {}) {
94
312
  document.documentElement.lang = language;
95
313
  document.documentElement.dir = this.dir;
96
314
 
315
+ // Kept in the URL so a reload lands in the same language — and because the
316
+ // form components read `?lang=` themselves when no language prop is set.
317
+ const url = new URL(window.location.href);
318
+
319
+ url.searchParams.set('lang', language);
320
+ window.history.replaceState({}, '', url);
321
+
97
322
  this.write('language', `${language} · ${this.dir}`);
98
323
  },
99
324
 
325
+ setOpen(open) {
326
+ this.open = open;
327
+
328
+ // Locked only where the drawer is a full-screen modal. On a desktop it opens
329
+ // on hover, and locking there would freeze the page under the pointer and
330
+ // shift the layout as the scrollbar goes. 64rem is Tailwind's `lg`.
331
+ const isModal = !window.matchMedia('(min-width: 64rem)').matches;
332
+
333
+ document.body.classList.toggle('overflow-hidden', open && isModal);
334
+ },
335
+
100
336
  setTheme(theme) {
101
337
  this.theme = theme;
102
338
 
@@ -113,12 +349,15 @@ window.harness = function harness(options = {}) {
113
349
  this.mode = mode;
114
350
  this.subject.isDev = mode === 'dev';
115
351
 
116
- this.write('mode', mode === 'dev' ? 'development · mock data' : `production · ${this.subject.baseUrl || 'no base-url set'}`);
352
+ this.write('mode', mode === 'dev' ? 'development · mock data' : `production · ${endpoint?.(this.subject) || 'no endpoint set'}`);
117
353
  },
118
354
 
119
355
  setWidth(width) {
120
356
  this.width = width;
121
- this.subject.closest('.frame')?.style.setProperty('--frame-w', width);
357
+
358
+ // Every frame on the page, so a gallery of several configurations resizes
359
+ // together instead of only wherever the subject happens to be.
360
+ document.querySelectorAll('.frame').forEach(frame => frame.style.setProperty('--frame-w', width));
122
361
 
123
362
  this.write('width', width);
124
363
  },
@@ -130,33 +369,63 @@ window.harness = function harness(options = {}) {
130
369
 
131
370
  try {
132
371
  data = (await window.loadMockData(config.mocks)) ?? {};
133
- await config.apply(this.subject, data);
372
+ this.data = data;
373
+
374
+ await apply?.(this.subject, data);
134
375
  } catch (error) {
135
376
  this.write('fixtures', `failed to load — ${error.message}`);
136
377
  }
137
378
 
138
379
  // Generated from the mock keys, never hand-listed: a hardcoded list drifts
139
380
  // the moment someone adds a scenario (R7). Labels only annotate.
140
- this.fixtures = [{ value: '', label: 'Empty' }, { value: 'error', label: 'Error' }, ...Object.keys(data).map(key => ({ value: key, label: key, note: config.labels[key] }))];
381
+ this.setFixtures(Object.keys(data), data);
382
+ },
383
+
384
+ /** Public, so a component that pushes its own mock set can feed the rail. */
385
+ setFixtures(keys, data) {
386
+ if (data) this.data = data;
387
+
388
+ // An annotated fixture always survives the filter. A label means someone
389
+ // picked that key deliberately — often precisely to show an empty or null
390
+ // state, which is the one case `has` would otherwise throw away.
391
+ const keep = key => Boolean(config.labels[key]) || Boolean(config.has(this.data?.[key], key));
392
+
393
+ this.keys = config.has ? keys.filter(keep) : keys;
394
+ this.hidden = keys.length - this.keys.length;
141
395
  },
142
396
 
143
397
  run(key) {
144
398
  this.fixture = key;
145
399
  this.write('fetch', key === '' ? '(empty)' : key);
146
400
 
147
- config.select(this.subject, key);
401
+ select?.(this.subject, key, this);
148
402
  },
149
403
 
150
404
  reload() {
151
405
  this.run(this.fixture ?? '');
152
406
  },
153
407
 
408
+ submit() {
409
+ this.subject?.submit?.();
410
+ },
411
+
154
412
  /* ---------- live events ---------- */
155
413
 
156
414
  observe() {
157
- this.subject.loadingStateChange = isLoading => this.write(isLoading ? 'loading' : 'idle', '');
158
- this.subject.errorCallback = message => this.write('error', String(message));
159
- this.subject.loadedResponse = response => this.write('loaded', summarise(response));
415
+ for (const [property, handler] of Object.entries(events)) {
416
+ this.subject[property] = (...args) => {
417
+ const line = handler.apply(this, args);
418
+
419
+ if (line) this.write(line[0], line[1]);
420
+
421
+ // The form components read this back — `!!callback(…)` is what decides
422
+ // whether the built-in success/error dialog opens, and true is what
423
+ // they do when no callback is set at all, so observing must not
424
+ // silently suppress it. A handler returning false opts out; every
425
+ // other callback ignores the value.
426
+ return line !== false;
427
+ };
428
+ }
160
429
  },
161
430
 
162
431
  write(label, detail) {
@@ -170,6 +439,7 @@ window.harness = function harness(options = {}) {
170
439
 
171
440
  function summarise(response) {
172
441
  if (!response) return '(nothing)';
442
+ if (typeof response !== 'object') return String(response);
173
443
 
174
444
  const vin = response.vin ?? response.identifiers?.vin;
175
445
  const keys = Object.keys(response).length;
@@ -179,86 +449,327 @@ function summarise(response) {
179
449
 
180
450
  /* ---------- the standard rail ---------- */
181
451
 
182
- const RAIL = /* html */ `
183
- <div class="flex items-center justify-between gap-3">
184
- <p class="eyebrow text-neutral font-bold">Harness</p>
185
- <a href="/" class="btn btn-xs btn-ghost gap-1.5" aria-label="Showcase home">
186
- <span class="adp-logo text-accent h-3.5 w-[34px]" aria-hidden="true"></span>
187
- Home
188
- </a>
189
- </div>
452
+ /**
453
+ * The navigation, read from catalog.json — one dropdown per area, every page in
454
+ * it. A hand-written nav on 26 pages is 26 places to forget a new demo, so the
455
+ * same rule as fixtures applies: generated, never listed (R7).
456
+ */
457
+ window.harnessNav = function harnessNav() {
458
+ return {
459
+ areas: [],
460
+ open: null,
461
+ path: window.location.pathname,
190
462
 
191
- <div class="flex flex-col gap-1.5">
192
- <span class="eyebrow text-neutral" x-text="'Language · ' + dir.toUpperCase()"></span>
193
- <div class="flex flex-wrap gap-1.5" role="group" aria-label="Language">
194
- <template x-for="item in languages" :key="item">
195
- <button type="button" class="btn btn-sm" :class="language === item ? 'btn-primary' : 'btn-outline'"
196
- :aria-pressed="language === item" @click="setLanguage(item)" x-text="item.toUpperCase()"></button>
197
- </template>
198
- </div>
199
- </div>
463
+ // Exposed because the NAV markup below binds `:href="site(page.path)"`, and
464
+ // Alpine resolves that name on this object rather than in module scope.
465
+ site,
466
+
467
+ async init() {
468
+ try {
469
+ const response = await fetch(new URL('catalog.json', import.meta.url));
470
+
471
+ if (!response.ok) return;
472
+
473
+ const catalog = await response.json();
474
+
475
+ this.areas = catalog.areas.map(area => ({ ...area, pages: catalog.pages.filter(page => page.area === area.id) }));
476
+ } catch {
477
+ // No catalog: the bar collapses to the wordmark, which still goes home.
478
+ }
479
+ },
200
480
 
201
- <template x-if="show.theme">
202
- <div class="flex flex-col gap-1.5">
203
- <span class="eyebrow text-neutral">Theme</span>
204
- <div class="flex flex-wrap gap-1.5" role="group" aria-label="Theme">
205
- <template x-for="item in ['system', 'light', 'dark']" :key="item">
206
- <button type="button" class="btn btn-sm capitalize" :class="theme === item ? 'btn-primary' : 'btn-outline'"
207
- :aria-pressed="theme === item" @click="setTheme(item)" x-text="item"></button>
481
+ /** Which area the page being viewed belongs to, so the bar says where you are. */
482
+ get area() {
483
+ return this.areas.find(group => group.pages.some(page => site(page.path) === this.path))?.id ?? null;
484
+ },
485
+
486
+ isCurrent(page) {
487
+ return site(page.path) === this.path;
488
+ },
489
+
490
+ toggle(id) {
491
+ this.open = this.open === id ? null : id;
492
+ },
493
+ };
494
+ };
495
+
496
+ /** Chevron, shared by every navigation trigger. */
497
+ const CHEVRON = /* html */ `
498
+ <svg class="h-3 w-3 opacity-60 transition-transform" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true">
499
+ <path d="m6 9 6 6 6-6" />
500
+ </svg>
501
+ `;
502
+
503
+ const NAV = /* html */ `
504
+ <div class="bg-base-100/90 border-base-300 sticky top-0 z-30 border-b border-dashed backdrop-blur">
505
+ <div class="mx-auto flex max-w-[1400px] items-center gap-2 px-4 py-2 sm:px-8" @click.outside="open = null" @keydown.escape.window="open = null">
506
+ <a :href="site('/')" class="btn btn-sm btn-ghost px-2" aria-label="Showcase home">
507
+ <span class="adp-logo text-accent h-4 w-[40px]" aria-hidden="true"></span>
508
+ </a>
509
+
510
+ <span class="bg-base-300 h-5 w-px" aria-hidden="true"></span>
511
+
512
+ <!-- Wide: one dropdown per area, so a group is one click away. -->
513
+ <nav class="hidden flex-wrap items-center gap-0.5 md:flex" aria-label="Demo pages">
514
+ <template x-for="group in areas" :key="group.id">
515
+ <div class="relative">
516
+ <button
517
+ type="button"
518
+ class="btn btn-sm btn-ghost gap-1.5"
519
+ :class="group.id === area && 'text-accent'"
520
+ :aria-expanded="open === group.id"
521
+ @click="toggle(group.id)"
522
+ >
523
+ <span x-text="group.label"></span>
524
+ <span class="badge badge-xs badge-ghost tabular-nums" x-text="group.count"></span>
525
+ <span :class="open === group.id && 'rotate-180'" class="transition-transform">${CHEVRON}</span>
526
+ </button>
527
+
528
+ <ul
529
+ class="menu bg-base-100 border-base-300 rounded-box absolute start-0 top-full z-50 mt-1 w-72 flex-nowrap border p-1 shadow-xl"
530
+ x-show="open === group.id"
531
+ x-transition:enter="transition ease-out duration-150"
532
+ x-transition:enter-start="opacity-0 -translate-y-1"
533
+ x-transition:leave="transition ease-in duration-100"
534
+ x-transition:leave-end="opacity-0"
535
+ >
536
+ <template x-for="page in group.pages" :key="page.path">
537
+ <li>
538
+ <a :href="site(page.path)" :class="isCurrent(page) && 'menu-active'" :aria-current="isCurrent(page) ? 'page' : null">
539
+ <span class="truncate" x-text="page.title"></span>
540
+ <span class="badge badge-xs badge-ghost ms-auto shrink-0" x-show="page.kind !== 'demo'" x-text="page.kind"></span>
541
+ </a>
542
+ </li>
543
+ </template>
544
+ </ul>
545
+ </div>
208
546
  </template>
547
+ </nav>
548
+
549
+ <!-- Narrow: the same tree, nested one level down, because six dropdowns do not fit. -->
550
+ <div class="relative md:hidden">
551
+ <button type="button" class="btn btn-sm btn-ghost gap-1.5" :aria-expanded="open === 'all'" @click="toggle('all')">
552
+ <span x-text="areas.find(group => group.id === area)?.label ?? 'Pages'"></span>
553
+ <span :class="open === 'all' && 'rotate-180'" class="transition-transform">${CHEVRON}</span>
554
+ </button>
555
+
556
+ <ul
557
+ class="menu bg-base-100 border-base-300 rounded-box absolute start-0 top-full z-50 mt-1 max-h-[70vh] w-[min(20rem,calc(100vw-2rem))] flex-nowrap overflow-y-auto border p-1 shadow-xl"
558
+ x-show="open === 'all'"
559
+ x-transition:enter="transition ease-out duration-150"
560
+ x-transition:enter-start="opacity-0 -translate-y-1"
561
+ x-transition:leave="transition ease-in duration-100"
562
+ x-transition:leave-end="opacity-0"
563
+ >
564
+ <template x-for="group in areas" :key="group.id">
565
+ <li>
566
+ <details :open="group.id === area">
567
+ <summary>
568
+ <span x-text="group.label"></span>
569
+ <span class="badge badge-xs badge-ghost tabular-nums" x-text="group.count"></span>
570
+ </summary>
571
+ <ul>
572
+ <template x-for="page in group.pages" :key="page.path">
573
+ <li>
574
+ <a :href="site(page.path)" :class="isCurrent(page) && 'menu-active'" :aria-current="isCurrent(page) ? 'page' : null" x-text="page.title"></a>
575
+ </li>
576
+ </template>
577
+ </ul>
578
+ </details>
579
+ </li>
580
+ </template>
581
+ </ul>
209
582
  </div>
210
583
  </div>
211
- </template>
584
+ </div>
585
+ `;
212
586
 
213
- <template x-if="show.mode">
214
- <div class="flex flex-col gap-1.5">
215
- <span class="eyebrow text-neutral">Mode</span>
216
- <div class="flex flex-wrap gap-1.5" role="group" aria-label="Mode">
217
- <template x-for="item in [{ value: 'dev', label: 'Development' }, { value: 'prod', label: 'Production' }]" :key="item.value">
218
- <button type="button" class="btn btn-sm" :class="mode === item.value ? 'btn-primary' : 'btn-outline'"
219
- :aria-pressed="mode === item.value" @click="setMode(item.value)" x-text="item.label"></button>
587
+ /*
588
+ * Mode and Fixtures sit ABOVE the component, not in the drawer. They are the two
589
+ * controls that get touched on every single interaction, and making someone open
590
+ * a panel to pick a VIN was the worst thing about the first pass. Everything
591
+ * you set once and forget language, theme, width, the log stays in the drawer.
592
+ */
593
+ const BAR = /* html */ `
594
+ <template x-if="show.bar">
595
+ <div class="card border-base-300 bg-base-100 flex flex-col gap-2 border border-dashed p-3">
596
+ <div class="flex flex-wrap items-start gap-x-5 gap-y-3">
597
+ <template x-if="show.mode">
598
+ <div class="flex shrink-0 items-center gap-2">
599
+ <span class="eyebrow text-neutral">Mode</span>
600
+ <div class="flex gap-1.5" role="group" aria-label="Mode">
601
+ <template x-for="item in [{ value: 'dev', label: 'Development' }, { value: 'prod', label: 'Production' }]" :key="item.value">
602
+ <button type="button" class="btn btn-xs" :class="mode === item.value ? 'btn-primary' : 'btn-outline'"
603
+ :aria-pressed="mode === item.value" @click="setMode(item.value)" x-text="item.label"></button>
604
+ </template>
605
+ </div>
606
+ </div>
220
607
  </template>
221
- </div>
222
- </div>
223
- </template>
224
608
 
225
- <template x-if="show.platform">
226
- <div class="flex flex-col gap-1.5">
227
- <span class="eyebrow text-neutral">Platform width</span>
228
- <div class="flex flex-wrap gap-1.5" role="group" aria-label="Platform width">
229
- <template x-for="item in platforms" :key="item.value">
230
- <button type="button" class="btn btn-sm" :class="width === item.value ? 'btn-primary' : 'btn-outline'"
231
- :aria-pressed="width === item.value" @click="setWidth(item.value)" x-text="item.label"></button>
609
+ <template x-if="show.fixtures">
610
+ <div class="flex min-w-0 flex-1 flex-wrap items-center gap-2">
611
+ <span class="eyebrow text-neutral">Fixtures</span>
612
+ <button type="button" class="btn btn-xs btn-outline" @click="reload()">Reload</button>
613
+
614
+ <div class="flex flex-wrap gap-1.5" role="group" aria-label="Fixtures">
615
+ <template x-for="item in fixtures" :key="item.value">
616
+ <button type="button" class="btn btn-xs font-mono font-normal" :class="fixture === item.value ? 'btn-primary' : 'btn-outline'"
617
+ :aria-pressed="fixture === item.value" @click="run(item.value)" :title="item.note || item.label">
618
+ <span x-text="item.label"></span>
619
+ <span class="font-sans opacity-70" x-show="item.note" x-text="item.note"></span>
620
+ </button>
621
+ </template>
622
+ </div>
623
+ </div>
232
624
  </template>
233
625
  </div>
626
+
627
+ <!-- Never a silent cut: a page that filters says how much it filtered. -->
628
+ <p class="text-base-content/50 text-xs" x-show="hidden" x-text="hidden + ' fixture(s) hidden — no data for this component'"></p>
234
629
  </div>
235
630
  </template>
631
+ `;
236
632
 
237
- <template x-if="show.fixtures">
238
- <div class="flex flex-col gap-1.5">
239
- <span class="eyebrow text-neutral">Fixtures</span>
240
- <button type="button" class="btn btn-sm btn-outline self-start" @click="reload()">Reload</button>
241
- <div class="flex flex-wrap gap-1.5" role="group" aria-label="Fixtures">
242
- <template x-for="item in fixtures" :key="item.value">
243
- <button type="button" class="btn btn-sm font-mono font-normal" :class="fixture === item.value ? 'btn-primary' : 'btn-outline'"
244
- :aria-pressed="fixture === item.value" @click="run(item.value)">
245
- <span x-text="item.label"></span>
246
- <span class="opacity-70 font-sans" x-show="item.note" x-text="item.note"></span>
247
- </button>
248
- </template>
249
- </div>
633
+ /** Sliders glyph, shared by both drawer launchers. */
634
+ const ICON = /* html */ `
635
+ <svg class="h-4 w-4 shrink-0" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" aria-hidden="true">
636
+ <path d="M4 6h10M18 6h2M4 12h2M10 12h10M4 18h10M18 18h2" />
637
+ <circle cx="16" cy="6" r="2" /><circle cx="8" cy="12" r="2" /><circle cx="16" cy="18" r="2" />
638
+ </svg>
639
+ `;
640
+
641
+ /*
642
+ * The rail is a drawer. On a desktop it advertises itself with a tab on the right
643
+ * edge — an invisible hover zone is only usable by someone who already knows it
644
+ * is there — and brushing anywhere along that edge opens it too. On a phone the
645
+ * tab would be a thumb trap, so it becomes a floating button instead. Escape,
646
+ * the close button and the scrim all get you back out.
647
+ *
648
+ * Everything here is pinned to the PHYSICAL right, not the inline end. The
649
+ * language control flips the page to RTL for half the supported set, and chrome
650
+ * that jumps to the other side of the screen when it does is disorienting — the
651
+ * component under test is what should mirror, not the tooling around it.
652
+ */
653
+ const RAIL = /* html */ `
654
+ <!-- Phone: a floating button, because an edge tab sits exactly where a thumb scrolls. -->
655
+ <button
656
+ type="button"
657
+ class="btn btn-sm btn-primary fixed right-4 bottom-4 z-40 gap-2 shadow-lg lg:hidden"
658
+ aria-controls="harness-panel"
659
+ :aria-expanded="open"
660
+ @click="setOpen(!open)"
661
+ >
662
+ ${ICON}
663
+ Harness
664
+ </button>
665
+
666
+ <!-- Desktop: a visible tab, so the drawer does not depend on anyone guessing it exists. -->
667
+ <button
668
+ type="button"
669
+ class="border-base-300 bg-base-100 text-base-content/70 hover:text-accent hover:border-accent/50 fixed top-1/2 right-0 z-30 hidden -translate-y-1/2 cursor-pointer flex-col items-center gap-2 rounded-l-xl border border-r-0 border-dashed py-4 pr-1.5 pl-2 shadow-md transition-colors lg:flex"
670
+ aria-controls="harness-panel"
671
+ :aria-expanded="open"
672
+ x-show="!open"
673
+ @mouseenter="setOpen(true)"
674
+ @click="setOpen(true)"
675
+ >
676
+ ${ICON}
677
+ <span class="eyebrow [writing-mode:vertical-rl] tracking-[0.16em]">Harness</span>
678
+ </button>
679
+
680
+ <!-- …and brushing the edge anywhere along it opens the drawer as well. -->
681
+ <div class="fixed inset-y-0 right-0 z-20 hidden w-2 lg:block" aria-hidden="true" @mouseenter="setOpen(true)"></div>
682
+
683
+ <!-- Phone only: there the drawer is a modal, so it needs something to dismiss against. -->
684
+ <div
685
+ class="bg-base-content/25 fixed inset-0 z-40 lg:hidden"
686
+ aria-hidden="true"
687
+ x-show="open"
688
+ x-transition:enter="transition ease-out duration-200"
689
+ x-transition:enter-start="opacity-0"
690
+ x-transition:leave="transition ease-in duration-150"
691
+ x-transition:leave-end="opacity-0"
692
+ @click="setOpen(false)"
693
+ ></div>
694
+
695
+ <aside
696
+ id="harness-panel"
697
+ class="border-base-300 bg-base-100 fixed inset-y-0 right-0 z-50 flex w-[21rem] max-w-[92vw] flex-col gap-4 overflow-y-auto border-l border-dashed p-4 shadow-2xl"
698
+ role="dialog"
699
+ aria-label="Harness controls"
700
+ x-show="open"
701
+ x-cloak
702
+ x-transition:enter="transition ease-out duration-200"
703
+ x-transition:enter-start="translate-x-full"
704
+ x-transition:leave="transition ease-in duration-150"
705
+ x-transition:leave-end="translate-x-full"
706
+ @mouseleave="matchMedia('(hover: hover)').matches && setOpen(false)"
707
+ @keydown.escape.window="setOpen(false)"
708
+ >
709
+ <div class="flex items-center justify-between gap-3">
710
+ <p class="eyebrow text-neutral font-bold">Harness</p>
711
+ <button type="button" class="btn btn-xs btn-ghost btn-square" aria-label="Close harness" @click="setOpen(false)">&times;</button>
250
712
  </div>
251
- </template>
252
713
 
253
- <template x-if="show.log">
254
- <div class="flex flex-col gap-1.5">
255
- <span class="eyebrow text-neutral">Live events</span>
256
- <pre class="log m-0 p-2.5 rounded-field bg-base-200 text-base-content/70 border border-base-300"><template x-if="!lines.length"><span>waiting…</span></template><template x-for="line in lines" :key="line.id"><span><b class="text-accent" x-text="line.label"></b> <span x-text="line.detail"></span>
257
- </span></template></pre>
714
+ <div class="border-base-300 flex flex-col gap-4 border-t pt-4">
715
+ <template x-if="show.language">
716
+ <div class="flex flex-col gap-1.5">
717
+ <span class="eyebrow text-neutral" x-text="'Language · ' + dir.toUpperCase()"></span>
718
+ <div class="flex flex-wrap gap-1.5" role="group" aria-label="Language">
719
+ <template x-for="item in languages" :key="item">
720
+ <button type="button" class="btn btn-sm" :class="language === item ? 'btn-primary' : 'btn-outline'"
721
+ :aria-pressed="language === item" @click="setLanguage(item)" x-text="item.toUpperCase()"></button>
722
+ </template>
723
+ </div>
724
+ </div>
725
+ </template>
726
+
727
+ <template x-if="show.theme">
728
+ <div class="flex flex-col gap-1.5">
729
+ <span class="eyebrow text-neutral">Theme</span>
730
+ <div class="flex flex-wrap gap-1.5" role="group" aria-label="Theme">
731
+ <template x-for="item in ['system', 'light', 'dark']" :key="item">
732
+ <button type="button" class="btn btn-sm capitalize" :class="theme === item ? 'btn-primary' : 'btn-outline'"
733
+ :aria-pressed="theme === item" @click="setTheme(item)" x-text="item"></button>
734
+ </template>
735
+ </div>
736
+ </div>
737
+ </template>
738
+
739
+ <template x-if="show.platform">
740
+ <div class="flex flex-col gap-1.5">
741
+ <span class="eyebrow text-neutral">Platform width</span>
742
+ <div class="flex flex-wrap gap-1.5" role="group" aria-label="Platform width">
743
+ <template x-for="item in platforms" :key="item.value">
744
+ <button type="button" class="btn btn-sm" :class="width === item.value ? 'btn-primary' : 'btn-outline'"
745
+ :aria-pressed="width === item.value" @click="setWidth(item.value)" x-text="item.label"></button>
746
+ </template>
747
+ </div>
748
+ </div>
749
+ </template>
258
750
  </div>
259
- </template>
751
+
752
+ <template x-if="show.log">
753
+ <div class="border-base-300 flex flex-col gap-1.5 border-t pt-4">
754
+ <span class="eyebrow text-neutral">Live events</span>
755
+ <pre class="log rounded-field bg-base-200 text-base-content/70 border-base-300 m-0 border p-2.5"><template x-if="!lines.length"><span>waiting…</span></template><template x-for="line in lines" :key="line.id"><span><b class="text-accent" x-text="line.label"></b> <span x-text="line.detail"></span>
756
+ </span></template></pre>
757
+ </div>
758
+ </template>
759
+ </aside>
260
760
  `;
261
761
 
762
+ document.querySelectorAll('[data-harness-nav]').forEach(nav => {
763
+ // Set before Alpine walks the tree — this module runs first, which is the same
764
+ // ordering the bar and the rail already rely on.
765
+ nav.setAttribute('x-data', 'harnessNav()');
766
+ nav.innerHTML = NAV;
767
+ });
768
+
769
+ document.querySelectorAll('[data-harness-bar]').forEach(bar => {
770
+ bar.innerHTML = BAR;
771
+ });
772
+
262
773
  document.querySelectorAll('[data-harness-rail]').forEach(rail => {
263
774
  rail.innerHTML = RAIL;
264
775
  });