@govbr-ds/webcomponents 2.1.3 → 2.3.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 (977) hide show
  1. package/README.md +146 -54
  2. package/cem/custom-elements.json +6496 -1141
  3. package/cem/webcomponents.html-custom-data.json +400 -287
  4. package/dist/cjs/br-avatar.cjs.entry.js +21 -14
  5. package/dist/cjs/br-breadcrumb-item.cjs.entry.js +2 -2
  6. package/dist/cjs/br-breadcrumb.cjs.entry.js +49 -22
  7. package/dist/cjs/br-button_2.cjs.entry.js +77 -35
  8. package/dist/cjs/br-card.cjs.entry.js +6 -5
  9. package/dist/cjs/br-carousel-page.cjs.entry.js +3 -3
  10. package/dist/cjs/br-carousel.cjs.entry.js +77 -21
  11. package/dist/cjs/br-checkbox-group.cjs.entry.js +157 -27
  12. package/dist/cjs/br-checkbox.cjs.entry.js +86 -16
  13. package/dist/cjs/br-checkgroup.cjs.entry.js +5 -2
  14. package/dist/cjs/br-collapse_2.cjs.entry.js +90 -27
  15. package/dist/cjs/br-cookiebar-cookie.cjs.entry.js +4 -4
  16. package/dist/cjs/br-cookiebar-group.cjs.entry.js +4 -4
  17. package/dist/cjs/br-cookiebar-header.cjs.entry.js +4 -4
  18. package/dist/cjs/br-cookiebar-link.cjs.entry.js +14 -6
  19. package/dist/cjs/br-cookiebar-note-group.cjs.entry.js +3 -5
  20. package/dist/cjs/br-cookiebar-note.cjs.entry.js +4 -4
  21. package/dist/cjs/br-cookiebar.cjs.entry.js +38 -25
  22. package/dist/cjs/br-crumb.cjs.entry.js +2 -2
  23. package/dist/cjs/br-date-picker_3.cjs.entry.js +246 -88
  24. package/dist/cjs/br-datetime-picker.cjs.entry.js +116 -528
  25. package/dist/cjs/br-divider.cjs.entry.js +70 -17
  26. package/dist/cjs/br-dropdown_2.cjs.entry.js +334 -163
  27. package/dist/cjs/br-footer-category.cjs.entry.js +10 -6
  28. package/dist/cjs/br-footer-item.cjs.entry.js +9 -4
  29. package/dist/cjs/br-footer-legal.cjs.entry.js +4 -4
  30. package/dist/cjs/br-footer-logo.cjs.entry.js +22 -10
  31. package/dist/cjs/br-footer-social.cjs.entry.js +14 -6
  32. package/dist/cjs/br-footer.cjs.entry.js +16 -7
  33. package/dist/cjs/br-header-function.cjs.entry.js +28 -7
  34. package/dist/cjs/br-header-link.cjs.entry.js +25 -4
  35. package/dist/cjs/br-header-list.cjs.entry.js +6 -17
  36. package/dist/cjs/br-header-logo.cjs.entry.js +18 -7
  37. package/dist/cjs/br-header.cjs.entry.js +96 -37
  38. package/dist/cjs/br-icon.cjs.entry.js +161 -53
  39. package/dist/cjs/br-input.cjs.entry.js +150 -40
  40. package/dist/cjs/br-item.cjs.entry.js +97 -48
  41. package/dist/cjs/br-link.cjs.entry.js +20 -7
  42. package/dist/cjs/br-loading.cjs.entry.js +100 -38
  43. package/dist/cjs/br-magic-button.cjs.entry.js +39 -9
  44. package/dist/cjs/br-menu-group.cjs.entry.js +14 -3
  45. package/dist/cjs/br-menu-header.cjs.entry.js +4 -4
  46. package/dist/cjs/br-menu-info.cjs.entry.js +4 -4
  47. package/dist/cjs/br-menu-item.cjs.entry.js +27 -5
  48. package/dist/cjs/br-menu-link.cjs.entry.js +14 -6
  49. package/dist/cjs/br-menu-list.cjs.entry.js +23 -27
  50. package/dist/cjs/br-menu-logo.cjs.entry.js +4 -4
  51. package/dist/cjs/br-menu-social.cjs.entry.js +16 -6
  52. package/dist/cjs/br-menu.cjs.entry.js +38 -57
  53. package/dist/cjs/br-modal.cjs.entry.js +44 -42
  54. package/dist/cjs/br-notification-body.cjs.entry.js +4 -4
  55. package/dist/cjs/br-notification-header.cjs.entry.js +4 -4
  56. package/dist/cjs/br-notification-item.cjs.entry.js +14 -8
  57. package/dist/cjs/br-notification.cjs.entry.js +23 -8
  58. package/dist/cjs/br-pagination.cjs.entry.js +120 -88
  59. package/dist/cjs/br-radio-group.cjs.entry.js +107 -58
  60. package/dist/cjs/br-radio.cjs.entry.js +62 -12
  61. package/dist/cjs/br-scrim.cjs.entry.js +161 -67
  62. package/dist/cjs/br-select-input_3.cjs.entry.js +286 -91
  63. package/dist/cjs/br-sign-in.cjs.entry.js +38 -15
  64. package/dist/cjs/br-skip-link-item.cjs.entry.js +39 -2
  65. package/dist/cjs/br-skip-link.cjs.entry.js +50 -33
  66. package/dist/cjs/br-skiplink-item.cjs.entry.js +22 -6
  67. package/dist/cjs/br-slider.cjs.entry.js +522 -100
  68. package/dist/cjs/br-step_2.cjs.entry.js +98 -44
  69. package/dist/cjs/br-switch.cjs.entry.js +21 -12
  70. package/dist/cjs/br-tab-item.cjs.entry.js +38 -14
  71. package/dist/cjs/br-tab.cjs.entry.js +89 -51
  72. package/dist/cjs/br-table-body.cjs.entry.js +3 -3
  73. package/dist/cjs/br-table-cell.cjs.entry.js +30 -13
  74. package/dist/cjs/br-table-header-cell.cjs.entry.js +23 -7
  75. package/dist/cjs/br-table-header.cjs.entry.js +3 -3
  76. package/dist/cjs/br-table-row.cjs.entry.js +17 -3
  77. package/dist/cjs/br-table.cjs.entry.js +67 -21
  78. package/dist/cjs/br-tag.cjs.entry.js +49 -31
  79. package/dist/cjs/br-textarea.cjs.entry.js +118 -13
  80. package/dist/cjs/br-tooltip.cjs.entry.js +87 -41
  81. package/dist/cjs/br-upload.cjs.entry.js +84 -25
  82. package/dist/cjs/br-wizard-panel.cjs.entry.js +16 -3
  83. package/dist/cjs/br-wizard.cjs.entry.js +52 -28
  84. package/dist/cjs/{isValid-Fu3kaWNn.js → datetime-picker-props-validation-DmNKSXsy.js} +481 -4
  85. package/dist/cjs/{floating-ui-MBI1osio.js → floating-ui-B6nsdYUU.js} +24 -1
  86. package/dist/cjs/{floating-ui.dom-BUSTaaxR.js → floating-ui.dom-wzdGZjyG.js} +201 -113
  87. package/dist/cjs/{focus-DuywwJPR.js → focus-BhfJnFgJ.js} +21 -0
  88. package/dist/cjs/header-context-CdawuLsH.js +17 -0
  89. package/dist/cjs/icon.utils-DF6kMskA.js +46 -0
  90. package/dist/cjs/id-DE4jSi-L.js +36 -0
  91. package/dist/cjs/{index-CRdcutym.js → index-Bc30P_6z.js} +88 -766
  92. package/dist/cjs/loader.cjs.js +2 -2
  93. package/dist/cjs/motion-CgIooxWS.js +29 -0
  94. package/dist/cjs/ownership-UnpufyCx.js +116 -0
  95. package/dist/cjs/prop-warning-xvEHQz8H.js +60 -0
  96. package/dist/cjs/props-D8dybmr0.js +124 -0
  97. package/dist/cjs/{swipe-BU8_XE9f.js → swipe-BGF-h9WY.js} +11 -1
  98. package/dist/cjs/{validator-CTCajtT9.js → validator-GkkueMOx.js} +18 -0
  99. package/dist/cjs/webcomponents.cjs.js +3 -3
  100. package/dist/collection/collection-manifest.json +1 -1
  101. package/dist/collection/components/avatar/avatar.css +1 -1
  102. package/dist/collection/components/avatar/avatar.js +48 -16
  103. package/dist/collection/components/breadcrumb/breadcrumb-item/breadcrumb-item.js +15 -3
  104. package/dist/collection/components/breadcrumb/breadcrumb.css +1 -1
  105. package/dist/collection/components/breadcrumb/breadcrumb.js +107 -22
  106. package/dist/collection/components/breadcrumb/crumb/crumb.js +14 -2
  107. package/dist/collection/components/button/button.css +1 -1
  108. package/dist/collection/components/button/button.js +93 -24
  109. package/dist/collection/components/card/card.css +1 -1
  110. package/dist/collection/components/card/card.js +33 -5
  111. package/dist/collection/components/carousel/carousel-page/carousel-page.css +1 -1
  112. package/dist/collection/components/carousel/carousel-page/carousel-page.js +11 -4
  113. package/dist/collection/components/carousel/carousel.css +1 -1
  114. package/dist/collection/components/carousel/carousel.js +107 -21
  115. package/dist/collection/components/checkbox/checkbox.css +1 -1
  116. package/dist/collection/components/checkbox/checkbox.js +134 -20
  117. package/dist/collection/components/checkbox-group/checkbox-group.css +1 -1
  118. package/dist/collection/components/checkbox-group/checkbox-group.js +210 -30
  119. package/dist/collection/components/checkgroup/checkgroup.js +42 -4
  120. package/dist/collection/components/collapse/collapse.css +1 -1
  121. package/dist/collection/components/collapse/collapse.js +55 -9
  122. package/dist/collection/components/cookiebar/cookiebar-cookie/cookiebar-cookie.css +1 -1
  123. package/dist/collection/components/cookiebar/cookiebar-cookie/cookiebar-cookie.js +17 -4
  124. package/dist/collection/components/cookiebar/cookiebar-group/cookiebar-group.css +1 -1
  125. package/dist/collection/components/cookiebar/cookiebar-group/cookiebar-group.js +16 -7
  126. package/dist/collection/components/cookiebar/cookiebar-header/cookiebar-header.css +1 -1
  127. package/dist/collection/components/cookiebar/cookiebar-header/cookiebar-header.js +15 -9
  128. package/dist/collection/components/cookiebar/cookiebar-link/cookiebar-link.css +1 -1
  129. package/dist/collection/components/cookiebar/cookiebar-link/cookiebar-link.js +24 -8
  130. package/dist/collection/components/cookiebar/cookiebar-note/cookiebar-note.css +1 -1
  131. package/dist/collection/components/cookiebar/cookiebar-note/cookiebar-note.js +14 -4
  132. package/dist/collection/components/cookiebar/cookiebar-note-group/cookiebar-note-group.css +1 -1
  133. package/dist/collection/components/cookiebar/cookiebar-note-group/cookiebar-note-group.js +13 -5
  134. package/dist/collection/components/cookiebar/cookiebar.css +1 -1
  135. package/dist/collection/components/cookiebar/cookiebar.js +67 -32
  136. package/dist/collection/components/datetime-picker/date-picker/date-picker.css +1 -1
  137. package/dist/collection/components/datetime-picker/date-picker/date-picker.js +134 -35
  138. package/dist/collection/components/datetime-picker/datetime-input/datetime-input.css +1 -1
  139. package/dist/collection/components/datetime-picker/datetime-input/datetime-input.js +112 -22
  140. package/dist/collection/components/datetime-picker/datetime-picker-props-validation.js +13 -5
  141. package/dist/collection/components/datetime-picker/datetime-picker.css +1 -1
  142. package/dist/collection/components/datetime-picker/datetime-picker.js +158 -42
  143. package/dist/collection/components/datetime-picker/time-picker/time-picker.css +1 -1
  144. package/dist/collection/components/datetime-picker/time-picker/time-picker.js +78 -9
  145. package/dist/collection/components/divider/divider.css +1 -1
  146. package/dist/collection/components/divider/divider.js +101 -26
  147. package/dist/collection/components/dropdown/dropdown.css +1 -1
  148. package/dist/collection/components/dropdown/dropdown.js +195 -51
  149. package/dist/collection/components/footer/footer-category/footer-category.css +1 -1
  150. package/dist/collection/components/footer/footer-category/footer-category.js +23 -4
  151. package/dist/collection/components/footer/footer-item/footer-item.css +1 -1
  152. package/dist/collection/components/footer/footer-item/footer-item.js +21 -2
  153. package/dist/collection/components/footer/footer-legal/footer-legal.css +1 -1
  154. package/dist/collection/components/footer/footer-legal/footer-legal.js +16 -2
  155. package/dist/collection/components/footer/footer-logo/footer-logo.css +1 -1
  156. package/dist/collection/components/footer/footer-logo/footer-logo.js +35 -9
  157. package/dist/collection/components/footer/footer-social/footer-social.css +1 -1
  158. package/dist/collection/components/footer/footer-social/footer-social.js +26 -6
  159. package/dist/collection/components/footer/footer.css +1 -1
  160. package/dist/collection/components/footer/footer.js +48 -7
  161. package/dist/collection/components/header/header-context.js +13 -0
  162. package/dist/collection/components/header/header-function/header-function.css +1 -1
  163. package/dist/collection/components/header/header-function/header-function.js +51 -8
  164. package/dist/collection/components/header/header-link/header-link.css +1 -1
  165. package/dist/collection/components/header/header-link/header-link.js +52 -2
  166. package/dist/collection/components/header/header-list/header-list.css +1 -1
  167. package/dist/collection/components/header/header-list/header-list.js +20 -23
  168. package/dist/collection/components/header/header-logo/header-logo.css +1 -1
  169. package/dist/collection/components/header/header-logo/header-logo.js +33 -8
  170. package/dist/collection/components/header/header.css +1 -1
  171. package/dist/collection/components/header/header.js +134 -44
  172. package/dist/collection/components/icon/default-icons-cache.js +111 -3
  173. package/dist/collection/components/icon/icon.css +1 -1
  174. package/dist/collection/components/icon/icon.js +80 -33
  175. package/dist/collection/components/icon/icon.utils.js +8 -0
  176. package/dist/collection/components/input/input.css +1 -1
  177. package/dist/collection/components/input/input.js +189 -55
  178. package/dist/collection/components/item/item.css +1 -1
  179. package/dist/collection/components/item/item.js +136 -52
  180. package/dist/collection/components/link/link.css +1 -1
  181. package/dist/collection/components/link/link.js +48 -15
  182. package/dist/collection/components/list/list.css +1 -1
  183. package/dist/collection/components/list/list.js +106 -25
  184. package/dist/collection/components/loading/loading.css +1 -1
  185. package/dist/collection/components/loading/loading.js +131 -43
  186. package/dist/collection/components/magic-button/magic-button.css +1 -1
  187. package/dist/collection/components/magic-button/magic-button.js +65 -9
  188. package/dist/collection/components/menu/menu-group/menu-group.css +1 -1
  189. package/dist/collection/components/menu/menu-group/menu-group.js +60 -2
  190. package/dist/collection/components/menu/menu-header/menu-header.css +1 -1
  191. package/dist/collection/components/menu/menu-header/menu-header.js +17 -2
  192. package/dist/collection/components/menu/menu-info/menu-info.css +1 -1
  193. package/dist/collection/components/menu/menu-info/menu-info.js +15 -2
  194. package/dist/collection/components/menu/menu-item/menu-item.css +1 -1
  195. package/dist/collection/components/menu/menu-item/menu-item.js +72 -8
  196. package/dist/collection/components/menu/menu-link/menu-link.css +1 -1
  197. package/dist/collection/components/menu/menu-link/menu-link.js +25 -4
  198. package/dist/collection/components/menu/menu-list/menu-list.css +1 -1
  199. package/dist/collection/components/menu/menu-list/menu-list.js +64 -29
  200. package/dist/collection/components/menu/menu-logo/menu-logo.css +1 -1
  201. package/dist/collection/components/menu/menu-logo/menu-logo.js +15 -2
  202. package/dist/collection/components/menu/menu-social/menu-social.css +1 -1
  203. package/dist/collection/components/menu/menu-social/menu-social.js +29 -7
  204. package/dist/collection/components/menu/menu.css +1 -1
  205. package/dist/collection/components/menu/menu.js +71 -60
  206. package/dist/collection/components/menu/menu.utils.js +8 -18
  207. package/dist/collection/components/message/message.css +1 -1
  208. package/dist/collection/components/message/message.js +50 -24
  209. package/dist/collection/components/modal/modal.css +1 -1
  210. package/dist/collection/components/modal/modal.js +72 -43
  211. package/dist/collection/components/notification/notification-body/notification-body.css +1 -1
  212. package/dist/collection/components/notification/notification-body/notification-body.js +13 -4
  213. package/dist/collection/components/notification/notification-header/notification-header.css +1 -1
  214. package/dist/collection/components/notification/notification-header/notification-header.js +13 -4
  215. package/dist/collection/components/notification/notification-item/notification-item.css +1 -1
  216. package/dist/collection/components/notification/notification-item/notification-item.js +23 -9
  217. package/dist/collection/components/notification/notification.css +1 -1
  218. package/dist/collection/components/notification/notification.js +54 -10
  219. package/dist/collection/components/pagination/pagination.css +1 -1
  220. package/dist/collection/components/pagination/pagination.js +164 -75
  221. package/dist/collection/components/radio/radio.css +1 -1
  222. package/dist/collection/components/radio/radio.js +109 -14
  223. package/dist/collection/components/radio-group/radio-group.css +1 -1
  224. package/dist/collection/components/radio-group/radio-group.js +153 -63
  225. package/dist/collection/components/scrim/scrim.css +1 -1
  226. package/dist/collection/components/scrim/scrim.js +215 -74
  227. package/dist/collection/components/scrim/scrim.utils.js +5 -51
  228. package/dist/collection/components/select/select-input/select-input.css +1 -1
  229. package/dist/collection/components/select/select-input/select-input.js +61 -6
  230. package/dist/collection/components/select/select-list/select-list.css +1 -1
  231. package/dist/collection/components/select/select-list/select-list.js +247 -52
  232. package/dist/collection/components/select/select-option/select-option.css +1 -1
  233. package/dist/collection/components/select/select-option/select-option.js +108 -46
  234. package/dist/collection/components/select/select.css +1 -1
  235. package/dist/collection/components/select/select.js +320 -124
  236. package/dist/collection/components/select/select.utils.js +3 -1
  237. package/dist/collection/components/sign-in/sign-in.css +1 -1
  238. package/dist/collection/components/sign-in/sign-in.js +60 -17
  239. package/dist/collection/components/skip-link/skip-link-item/skip-link-item-alias.js +112 -3
  240. package/dist/collection/components/skip-link/skip-link-item/skip-link-item.css +1 -1
  241. package/dist/collection/components/skip-link/skip-link-item/skip-link-item.js +58 -5
  242. package/dist/collection/components/skip-link/skip-link.css +1 -1
  243. package/dist/collection/components/skip-link/skip-link.js +78 -39
  244. package/dist/collection/components/slider/slider.css +1 -1
  245. package/dist/collection/components/slider/slider.js +530 -132
  246. package/dist/collection/components/slider/slider.utils.js +178 -0
  247. package/dist/collection/components/step/step-item/step-item.css +1 -1
  248. package/dist/collection/components/step/step-item/step-item.js +29 -12
  249. package/dist/collection/components/step/step.css +1 -1
  250. package/dist/collection/components/step/step.js +119 -44
  251. package/dist/collection/components/switch/switch.css +1 -1
  252. package/dist/collection/components/switch/switch.js +48 -15
  253. package/dist/collection/components/tab/tab-item/tab-item.css +1 -1
  254. package/dist/collection/components/tab/tab-item/tab-item.js +49 -14
  255. package/dist/collection/components/tab/tab.css +1 -1
  256. package/dist/collection/components/tab/tab.js +123 -53
  257. package/dist/collection/components/table/table-body/table-body.css +1 -1
  258. package/dist/collection/components/table/table-body/table-body.js +11 -7
  259. package/dist/collection/components/table/table-cell/table-cell.css +1 -1
  260. package/dist/collection/components/table/table-cell/table-cell.js +36 -17
  261. package/dist/collection/components/table/table-header/table-header.css +1 -1
  262. package/dist/collection/components/table/table-header/table-header.js +11 -7
  263. package/dist/collection/components/table/table-header-cell/table-header-cell.css +1 -1
  264. package/dist/collection/components/table/table-header-cell/table-header-cell.js +35 -13
  265. package/dist/collection/components/table/table-row/table-row.css +1 -1
  266. package/dist/collection/components/table/table-row/table-row.js +24 -7
  267. package/dist/collection/components/table/table.css +1 -1
  268. package/dist/collection/components/table/table.js +107 -31
  269. package/dist/collection/components/tag/tag.css +1 -1
  270. package/dist/collection/components/tag/tag.js +86 -36
  271. package/dist/collection/components/textarea/textarea.css +1 -1
  272. package/dist/collection/components/textarea/textarea.js +222 -19
  273. package/dist/collection/components/tooltip/tooltip.css +1 -1
  274. package/dist/collection/components/tooltip/tooltip.js +134 -45
  275. package/dist/collection/components/upload/upload.css +1 -1
  276. package/dist/collection/components/upload/upload.js +135 -33
  277. package/dist/collection/components/wizard/wizard-panel/wizard-panel.css +1 -1
  278. package/dist/collection/components/wizard/wizard-panel/wizard-panel.js +54 -3
  279. package/dist/collection/components/wizard/wizard.css +1 -1
  280. package/dist/collection/components/wizard/wizard.js +82 -28
  281. package/dist/collection/pages/components/select/remote.js +33 -0
  282. package/dist/collection/pages/components/select/virtualized.js +13 -0
  283. package/dist/collection/pages/components/upload/handler.js +25 -0
  284. package/dist/collection/pages/scripts/component-controls-core.js +95 -0
  285. package/dist/collection/pages/scripts/component-controls.js +221 -158
  286. package/dist/collection/pages/scripts/dev-event-console.js +5 -1
  287. package/dist/collection/pages/scripts/menu.js +90 -6
  288. package/dist/collection/pages/scripts/pageLoader.js +1570 -607
  289. package/dist/collection/pages/scripts/pageloader-preview.js +796 -0
  290. package/dist/collection/pages/scripts/playground-core.js +173 -0
  291. package/dist/collection/shared/utils/cssVariables.js +2 -0
  292. package/dist/collection/shared/utils/date.js +8 -4
  293. package/dist/collection/shared/utils/floating-ui.js +24 -1
  294. package/dist/collection/shared/utils/focus.js +31 -0
  295. package/dist/collection/shared/utils/form.js +17 -0
  296. package/dist/collection/shared/utils/getRandom.js +16 -1
  297. package/dist/collection/shared/utils/helpers.js +4 -11
  298. package/dist/collection/shared/utils/id.js +23 -7
  299. package/dist/collection/shared/utils/index.js +6 -1
  300. package/dist/collection/shared/utils/isEmpty.js +5 -3
  301. package/dist/collection/shared/utils/motion.js +25 -0
  302. package/dist/collection/shared/utils/ownership.js +113 -0
  303. package/dist/collection/shared/utils/prop-warning.js +47 -0
  304. package/dist/collection/shared/utils/props.js +79 -0
  305. package/dist/collection/shared/utils/swipe.js +11 -1
  306. package/dist/collection/shared/utils/transition.js +3 -0
  307. package/dist/collection/shared/utils/virtual-scroll.js +24 -0
  308. package/dist/components/br-avatar.d.ts +1 -1
  309. package/dist/components/br-avatar.js +1 -1
  310. package/dist/components/br-breadcrumb-item.d.ts +1 -1
  311. package/dist/components/br-breadcrumb-item.js +1 -1
  312. package/dist/components/br-breadcrumb.d.ts +1 -1
  313. package/dist/components/br-breadcrumb.js +1 -1
  314. package/dist/components/br-button.d.ts +1 -1
  315. package/dist/components/br-button.js +1 -1
  316. package/dist/components/br-card.d.ts +1 -1
  317. package/dist/components/br-card.js +1 -1
  318. package/dist/components/br-carousel-page.d.ts +1 -1
  319. package/dist/components/br-carousel-page.js +1 -1
  320. package/dist/components/br-carousel.d.ts +1 -1
  321. package/dist/components/br-carousel.js +1 -1
  322. package/dist/components/br-checkbox-group.d.ts +1 -1
  323. package/dist/components/br-checkbox-group.js +1 -1
  324. package/dist/components/br-checkbox.d.ts +1 -1
  325. package/dist/components/br-checkbox.js +1 -1
  326. package/dist/components/br-checkgroup.d.ts +1 -1
  327. package/dist/components/br-checkgroup.js +1 -1
  328. package/dist/components/br-collapse.d.ts +1 -1
  329. package/dist/components/br-collapse.js +1 -1
  330. package/dist/components/br-cookiebar-cookie.d.ts +1 -1
  331. package/dist/components/br-cookiebar-cookie.js +1 -1
  332. package/dist/components/br-cookiebar-group.d.ts +1 -1
  333. package/dist/components/br-cookiebar-group.js +1 -1
  334. package/dist/components/br-cookiebar-header.d.ts +1 -1
  335. package/dist/components/br-cookiebar-header.js +1 -1
  336. package/dist/components/br-cookiebar-link.d.ts +1 -1
  337. package/dist/components/br-cookiebar-link.js +1 -1
  338. package/dist/components/br-cookiebar-note-group.d.ts +1 -1
  339. package/dist/components/br-cookiebar-note-group.js +1 -1
  340. package/dist/components/br-cookiebar-note.d.ts +1 -1
  341. package/dist/components/br-cookiebar-note.js +1 -1
  342. package/dist/components/br-cookiebar.d.ts +1 -1
  343. package/dist/components/br-cookiebar.js +1 -1
  344. package/dist/components/br-crumb.d.ts +1 -1
  345. package/dist/components/br-crumb.js +1 -1
  346. package/dist/components/br-date-picker.d.ts +1 -1
  347. package/dist/components/br-date-picker.js +1 -1
  348. package/dist/components/br-datetime-input.d.ts +1 -1
  349. package/dist/components/br-datetime-input.js +1 -1
  350. package/dist/components/br-datetime-picker.d.ts +1 -1
  351. package/dist/components/br-datetime-picker.js +1 -1
  352. package/dist/components/br-divider.d.ts +1 -1
  353. package/dist/components/br-divider.js +1 -1
  354. package/dist/components/br-dropdown.d.ts +1 -1
  355. package/dist/components/br-dropdown.js +1 -1
  356. package/dist/components/br-footer-category.d.ts +1 -1
  357. package/dist/components/br-footer-category.js +1 -1
  358. package/dist/components/br-footer-item.d.ts +1 -1
  359. package/dist/components/br-footer-item.js +1 -1
  360. package/dist/components/br-footer-legal.d.ts +1 -1
  361. package/dist/components/br-footer-legal.js +1 -1
  362. package/dist/components/br-footer-logo.d.ts +1 -1
  363. package/dist/components/br-footer-logo.js +1 -1
  364. package/dist/components/br-footer-social.d.ts +1 -1
  365. package/dist/components/br-footer-social.js +1 -1
  366. package/dist/components/br-footer.d.ts +1 -1
  367. package/dist/components/br-footer.js +1 -1
  368. package/dist/components/br-header-function.d.ts +1 -1
  369. package/dist/components/br-header-function.js +1 -1
  370. package/dist/components/br-header-link.d.ts +1 -1
  371. package/dist/components/br-header-link.js +1 -1
  372. package/dist/components/br-header-list.d.ts +1 -1
  373. package/dist/components/br-header-list.js +1 -1
  374. package/dist/components/br-header-logo.d.ts +1 -1
  375. package/dist/components/br-header-logo.js +1 -1
  376. package/dist/components/br-header.d.ts +1 -1
  377. package/dist/components/br-header.js +1 -1
  378. package/dist/components/br-icon.d.ts +1 -1
  379. package/dist/components/br-icon.js +1 -1
  380. package/dist/components/br-input.d.ts +1 -1
  381. package/dist/components/br-input.js +1 -1
  382. package/dist/components/br-item.d.ts +1 -1
  383. package/dist/components/br-item.js +1 -1
  384. package/dist/components/br-link.d.ts +1 -1
  385. package/dist/components/br-link.js +1 -1
  386. package/dist/components/br-list.d.ts +1 -1
  387. package/dist/components/br-list.js +1 -1
  388. package/dist/components/br-loading.d.ts +1 -1
  389. package/dist/components/br-loading.js +1 -1
  390. package/dist/components/br-magic-button.d.ts +1 -1
  391. package/dist/components/br-magic-button.js +1 -1
  392. package/dist/components/br-menu-group.d.ts +1 -1
  393. package/dist/components/br-menu-group.js +1 -1
  394. package/dist/components/br-menu-header.d.ts +1 -1
  395. package/dist/components/br-menu-header.js +1 -1
  396. package/dist/components/br-menu-info.d.ts +1 -1
  397. package/dist/components/br-menu-info.js +1 -1
  398. package/dist/components/br-menu-item.d.ts +1 -1
  399. package/dist/components/br-menu-item.js +1 -1
  400. package/dist/components/br-menu-link.d.ts +1 -1
  401. package/dist/components/br-menu-link.js +1 -1
  402. package/dist/components/br-menu-list.d.ts +1 -1
  403. package/dist/components/br-menu-list.js +1 -1
  404. package/dist/components/br-menu-logo.d.ts +1 -1
  405. package/dist/components/br-menu-logo.js +1 -1
  406. package/dist/components/br-menu-social.d.ts +1 -1
  407. package/dist/components/br-menu-social.js +1 -1
  408. package/dist/components/br-menu.d.ts +1 -1
  409. package/dist/components/br-menu.js +1 -1
  410. package/dist/components/br-message.d.ts +1 -1
  411. package/dist/components/br-message.js +1 -1
  412. package/dist/components/br-modal.d.ts +1 -1
  413. package/dist/components/br-modal.js +1 -1
  414. package/dist/components/br-notification-body.d.ts +1 -1
  415. package/dist/components/br-notification-body.js +1 -1
  416. package/dist/components/br-notification-header.d.ts +1 -1
  417. package/dist/components/br-notification-header.js +1 -1
  418. package/dist/components/br-notification-item.d.ts +1 -1
  419. package/dist/components/br-notification-item.js +1 -1
  420. package/dist/components/br-notification.d.ts +1 -1
  421. package/dist/components/br-notification.js +1 -1
  422. package/dist/components/br-pagination.d.ts +1 -1
  423. package/dist/components/br-pagination.js +1 -1
  424. package/dist/components/br-radio-group.d.ts +1 -1
  425. package/dist/components/br-radio-group.js +1 -1
  426. package/dist/components/br-radio.d.ts +1 -1
  427. package/dist/components/br-radio.js +1 -1
  428. package/dist/components/br-scrim.d.ts +1 -1
  429. package/dist/components/br-scrim.js +1 -1
  430. package/dist/components/br-select-input.d.ts +1 -1
  431. package/dist/components/br-select-input.js +1 -1
  432. package/dist/components/br-select-list.d.ts +1 -1
  433. package/dist/components/br-select-list.js +1 -1
  434. package/dist/components/br-select-option.d.ts +1 -1
  435. package/dist/components/br-select-option.js +1 -1
  436. package/dist/components/br-select.d.ts +1 -1
  437. package/dist/components/br-select.js +1 -1
  438. package/dist/components/br-sign-in.d.ts +1 -1
  439. package/dist/components/br-sign-in.js +1 -1
  440. package/dist/components/br-skip-link-item.d.ts +1 -1
  441. package/dist/components/br-skip-link-item.js +1 -1
  442. package/dist/components/br-skip-link.d.ts +1 -1
  443. package/dist/components/br-skip-link.js +1 -1
  444. package/dist/components/br-skiplink-item.d.ts +1 -1
  445. package/dist/components/br-skiplink-item.js +1 -1
  446. package/dist/components/br-slider.d.ts +1 -1
  447. package/dist/components/br-slider.js +1 -1
  448. package/dist/components/br-step-item.d.ts +1 -1
  449. package/dist/components/br-step-item.js +1 -1
  450. package/dist/components/br-step.d.ts +1 -1
  451. package/dist/components/br-step.js +1 -1
  452. package/dist/components/br-switch.d.ts +1 -1
  453. package/dist/components/br-switch.js +1 -1
  454. package/dist/components/br-tab-item.d.ts +1 -1
  455. package/dist/components/br-tab-item.js +1 -1
  456. package/dist/components/br-tab.d.ts +1 -1
  457. package/dist/components/br-tab.js +1 -1
  458. package/dist/components/br-table-body.d.ts +1 -1
  459. package/dist/components/br-table-body.js +1 -1
  460. package/dist/components/br-table-cell.d.ts +1 -1
  461. package/dist/components/br-table-cell.js +1 -1
  462. package/dist/components/br-table-header-cell.d.ts +1 -1
  463. package/dist/components/br-table-header-cell.js +1 -1
  464. package/dist/components/br-table-header.d.ts +1 -1
  465. package/dist/components/br-table-header.js +1 -1
  466. package/dist/components/br-table-row.d.ts +1 -1
  467. package/dist/components/br-table-row.js +1 -1
  468. package/dist/components/br-table.d.ts +1 -1
  469. package/dist/components/br-table.js +1 -1
  470. package/dist/components/br-tag.d.ts +1 -1
  471. package/dist/components/br-tag.js +1 -1
  472. package/dist/components/br-textarea.d.ts +1 -1
  473. package/dist/components/br-textarea.js +1 -1
  474. package/dist/components/br-time-picker.d.ts +1 -1
  475. package/dist/components/br-time-picker.js +1 -1
  476. package/dist/components/br-tooltip.d.ts +1 -1
  477. package/dist/components/br-tooltip.js +1 -1
  478. package/dist/components/br-upload.d.ts +1 -1
  479. package/dist/components/br-upload.js +1 -1
  480. package/dist/components/br-wizard-panel.d.ts +1 -1
  481. package/dist/components/br-wizard-panel.js +1 -1
  482. package/dist/components/br-wizard.d.ts +1 -1
  483. package/dist/components/br-wizard.js +1 -1
  484. package/dist/components/index.d.ts +89 -89
  485. package/dist/components/index.js +1 -1
  486. package/dist/components/p-0qmYp77w.js +5 -0
  487. package/dist/components/p-5c3rNBXh.js +5 -0
  488. package/dist/components/p-B8oIvH3q.js +5 -0
  489. package/dist/components/p-BECz8XWJ.js +5 -0
  490. package/dist/components/p-BEJGB0Nd.js +5 -0
  491. package/dist/{webcomponents/p-Dmfk7eEe.js → components/p-BJZC_NuV.js} +1 -1
  492. package/dist/components/p-BJtdabsr.js +5 -0
  493. package/dist/components/p-BM4Ys6hX.js +5 -0
  494. package/dist/components/p-BXWh9s7p.js +5 -0
  495. package/dist/components/{p-DA5GS53D.js → p-BblZlUp2.js} +1 -1
  496. package/dist/components/{p-C1yRmdso.js → p-BcqVlof7.js} +1 -1
  497. package/dist/components/p-BeJxz5TQ.js +5 -0
  498. package/dist/components/p-Bezou5CQ.js +5 -0
  499. package/dist/components/p-BjeUETWJ.js +5 -0
  500. package/dist/components/p-CDTENPaP.js +5 -0
  501. package/dist/components/p-CDtFCbKp.js +5 -0
  502. package/dist/components/p-CNwZRgyL.js +5 -0
  503. package/dist/components/p-CZZVc2gK.js +5 -0
  504. package/dist/components/p-Cd6udSDt.js +5 -0
  505. package/dist/components/p-Ci0_RqAE.js +5 -0
  506. package/dist/components/p-CuBgClZm.js +5 -0
  507. package/dist/components/p-D0QYZSoP.js +5 -0
  508. package/dist/components/p-D4SWpW6-.js +5 -0
  509. package/dist/components/p-D579DS7x.js +5 -0
  510. package/dist/components/p-D8K7rhHd.js +5 -0
  511. package/dist/components/p-D9Zo6FlV.js +5 -0
  512. package/dist/components/p-D9nXlCuS.js +5 -0
  513. package/dist/components/p-DKFO6Q_g.js +5 -0
  514. package/dist/components/p-DNJSSCNi.js +5 -0
  515. package/dist/components/p-DOJ1vYOl.js +5 -0
  516. package/dist/components/p-DWhzxlCx.js +5 -0
  517. package/dist/components/p-DYI30IZL.js +5 -0
  518. package/dist/components/p-DcVldfL0.js +5 -0
  519. package/dist/components/p-DhvmHPp4.js +5 -0
  520. package/dist/components/p-DiLI514I.js +5 -0
  521. package/dist/components/p-DwgiHL0b.js +5 -0
  522. package/dist/components/p-Jk_KQE5V.js +5 -0
  523. package/dist/components/p-Nze3Utvd.js +5 -0
  524. package/dist/components/p-WxDB6Dk4.js +5 -0
  525. package/dist/components/p-ZLoeVagg.js +5 -0
  526. package/dist/components/p-gbYJ9sfc.js +5 -0
  527. package/dist/components/p-uc8ABlC_.js +5 -0
  528. package/dist/components/p-v60ypfxD.js +5 -0
  529. package/dist/esm/br-avatar.entry.js +21 -14
  530. package/dist/esm/br-breadcrumb-item.entry.js +2 -2
  531. package/dist/esm/br-breadcrumb.entry.js +49 -22
  532. package/dist/esm/br-button_2.entry.js +77 -35
  533. package/dist/esm/br-card.entry.js +6 -5
  534. package/dist/esm/br-carousel-page.entry.js +3 -3
  535. package/dist/esm/br-carousel.entry.js +78 -22
  536. package/dist/esm/br-checkbox-group.entry.js +157 -27
  537. package/dist/esm/br-checkbox.entry.js +87 -17
  538. package/dist/esm/br-checkgroup.entry.js +5 -2
  539. package/dist/esm/br-collapse_2.entry.js +91 -28
  540. package/dist/esm/br-cookiebar-cookie.entry.js +4 -4
  541. package/dist/esm/br-cookiebar-group.entry.js +4 -4
  542. package/dist/esm/br-cookiebar-header.entry.js +4 -4
  543. package/dist/esm/br-cookiebar-link.entry.js +14 -6
  544. package/dist/esm/br-cookiebar-note-group.entry.js +3 -5
  545. package/dist/esm/br-cookiebar-note.entry.js +4 -4
  546. package/dist/esm/br-cookiebar.entry.js +39 -26
  547. package/dist/esm/br-crumb.entry.js +2 -2
  548. package/dist/esm/br-date-picker_3.entry.js +207 -49
  549. package/dist/esm/br-datetime-picker.entry.js +83 -495
  550. package/dist/esm/br-divider.entry.js +70 -17
  551. package/dist/esm/br-dropdown_2.entry.js +335 -164
  552. package/dist/esm/br-footer-category.entry.js +10 -6
  553. package/dist/esm/br-footer-item.entry.js +9 -4
  554. package/dist/esm/br-footer-legal.entry.js +4 -4
  555. package/dist/esm/br-footer-logo.entry.js +22 -10
  556. package/dist/esm/br-footer-social.entry.js +14 -6
  557. package/dist/esm/br-footer.entry.js +16 -7
  558. package/dist/esm/br-header-function.entry.js +28 -7
  559. package/dist/esm/br-header-link.entry.js +25 -4
  560. package/dist/esm/br-header-list.entry.js +7 -18
  561. package/dist/esm/br-header-logo.entry.js +18 -7
  562. package/dist/esm/br-header.entry.js +96 -37
  563. package/dist/esm/br-icon.entry.js +160 -52
  564. package/dist/esm/br-input.entry.js +152 -42
  565. package/dist/esm/br-item.entry.js +97 -48
  566. package/dist/esm/br-link.entry.js +20 -7
  567. package/dist/esm/br-loading.entry.js +100 -38
  568. package/dist/esm/br-magic-button.entry.js +39 -9
  569. package/dist/esm/br-menu-group.entry.js +14 -3
  570. package/dist/esm/br-menu-header.entry.js +4 -4
  571. package/dist/esm/br-menu-info.entry.js +4 -4
  572. package/dist/esm/br-menu-item.entry.js +27 -5
  573. package/dist/esm/br-menu-link.entry.js +14 -6
  574. package/dist/esm/br-menu-list.entry.js +23 -27
  575. package/dist/esm/br-menu-logo.entry.js +4 -4
  576. package/dist/esm/br-menu-social.entry.js +16 -6
  577. package/dist/esm/br-menu.entry.js +39 -58
  578. package/dist/esm/br-modal.entry.js +44 -42
  579. package/dist/esm/br-notification-body.entry.js +4 -4
  580. package/dist/esm/br-notification-header.entry.js +4 -4
  581. package/dist/esm/br-notification-item.entry.js +14 -8
  582. package/dist/esm/br-notification.entry.js +24 -9
  583. package/dist/esm/br-pagination.entry.js +120 -88
  584. package/dist/esm/br-radio-group.entry.js +108 -59
  585. package/dist/esm/br-radio.entry.js +63 -13
  586. package/dist/esm/br-scrim.entry.js +161 -67
  587. package/dist/esm/br-select-input_3.entry.js +286 -91
  588. package/dist/esm/br-sign-in.entry.js +38 -15
  589. package/dist/esm/br-skip-link-item.entry.js +39 -2
  590. package/dist/esm/br-skip-link.entry.js +50 -33
  591. package/dist/esm/br-skiplink-item.entry.js +22 -6
  592. package/dist/esm/br-slider.entry.js +520 -98
  593. package/dist/esm/br-step_2.entry.js +98 -44
  594. package/dist/esm/br-switch.entry.js +22 -13
  595. package/dist/esm/br-tab-item.entry.js +38 -14
  596. package/dist/esm/br-tab.entry.js +89 -51
  597. package/dist/esm/br-table-body.entry.js +3 -3
  598. package/dist/esm/br-table-cell.entry.js +30 -13
  599. package/dist/esm/br-table-header-cell.entry.js +23 -7
  600. package/dist/esm/br-table-header.entry.js +3 -3
  601. package/dist/esm/br-table-row.entry.js +17 -3
  602. package/dist/esm/br-table.entry.js +68 -22
  603. package/dist/esm/br-tag.entry.js +50 -32
  604. package/dist/esm/br-textarea.entry.js +119 -14
  605. package/dist/esm/br-tooltip.entry.js +88 -42
  606. package/dist/esm/br-upload.entry.js +85 -26
  607. package/dist/esm/br-wizard-panel.entry.js +16 -3
  608. package/dist/esm/br-wizard.entry.js +52 -28
  609. package/dist/esm/{datetime-picker-constants-Bfm58jO6.js → datetime-picker-constants-BtRPYRvA.js} +1 -1
  610. package/dist/esm/{isValid-DIUZX1qS.js → datetime-picker-props-validation-BeTcUTnE.js} +476 -5
  611. package/dist/esm/{event-DFN_so7I.js → event-CfuJQ1DY.js} +1 -1
  612. package/dist/esm/{floating-ui-BavFwMnx.js → floating-ui-CskvaxD5.js} +24 -1
  613. package/dist/esm/{floating-ui.dom-DIK54tTj.js → floating-ui.dom-D9Zo6FlV.js} +201 -114
  614. package/dist/esm/{focus-DxZJrIyL.js → focus-CNwZRgyL.js} +20 -1
  615. package/dist/esm/header-context-BEJGB0Nd.js +15 -0
  616. package/dist/esm/icon.utils-zlORkiHQ.js +43 -0
  617. package/dist/esm/id-BeJxz5TQ.js +34 -0
  618. package/dist/esm/{index-Bo-2igoO.js → index-BQPOWxe5.js} +1 -1
  619. package/dist/esm/{index-C2RBydfd.js → index-ConyRdJe.js} +88 -766
  620. package/dist/esm/index.js +2 -2
  621. package/dist/esm/loader.js +3 -3
  622. package/dist/esm/motion-DWhzxlCx.js +27 -0
  623. package/dist/esm/ownership-CDtFCbKp.js +111 -0
  624. package/dist/esm/prop-warning-BlGV-x0w.js +56 -0
  625. package/dist/esm/props-D07GjR4_.js +116 -0
  626. package/dist/esm/{swipe-Dmfk7eEe.js → swipe-BJZC_NuV.js} +11 -1
  627. package/dist/esm/{validator-D3tVP32U.js → validator-BkWWrDEr.js} +18 -1
  628. package/dist/esm/webcomponents.js +4 -4
  629. package/dist/hydrate/index.js +7541 -2577
  630. package/dist/hydrate/index.mjs +7541 -2577
  631. package/dist/loader/index.d.ts +1 -1
  632. package/dist/types/components/avatar/avatar.d.ts +34 -4
  633. package/dist/types/components/breadcrumb/breadcrumb-item/breadcrumb-item.d.ts +14 -2
  634. package/dist/types/components/breadcrumb/breadcrumb.d.ts +66 -5
  635. package/dist/types/components/breadcrumb/crumb/crumb.d.ts +13 -1
  636. package/dist/types/components/button/button.d.ts +45 -8
  637. package/dist/types/components/card/card.d.ts +31 -3
  638. package/dist/types/components/carousel/carousel-page/carousel-page.d.ts +10 -3
  639. package/dist/types/components/carousel/carousel.d.ts +46 -3
  640. package/dist/types/components/checkbox/checkbox.d.ts +59 -6
  641. package/dist/types/components/checkbox-group/checkbox-group.d.ts +47 -5
  642. package/dist/types/components/checkgroup/checkgroup.d.ts +27 -5
  643. package/dist/types/components/collapse/collapse.d.ts +37 -4
  644. package/dist/types/components/cookiebar/cookiebar-cookie/cookiebar-cookie.d.ts +16 -3
  645. package/dist/types/components/cookiebar/cookiebar-group/cookiebar-group.d.ts +15 -6
  646. package/dist/types/components/cookiebar/cookiebar-header/cookiebar-header.d.ts +14 -8
  647. package/dist/types/components/cookiebar/cookiebar-link/cookiebar-link.d.ts +16 -5
  648. package/dist/types/components/cookiebar/cookiebar-note/cookiebar-note.d.ts +13 -3
  649. package/dist/types/components/cookiebar/cookiebar-note-group/cookiebar-note-group.d.ts +13 -3
  650. package/dist/types/components/cookiebar/cookiebar.d.ts +35 -10
  651. package/dist/types/components/datetime-picker/date-picker/date-picker.d.ts +63 -7
  652. package/dist/types/components/datetime-picker/datetime-input/datetime-input.d.ts +51 -9
  653. package/dist/types/components/datetime-picker/datetime-picker-props-validation.d.ts +4 -2
  654. package/dist/types/components/datetime-picker/datetime-picker.d.ts +118 -12
  655. package/dist/types/components/datetime-picker/time-picker/time-picker.d.ts +38 -4
  656. package/dist/types/components/divider/divider.d.ts +45 -8
  657. package/dist/types/components/dropdown/dropdown.d.ts +53 -7
  658. package/dist/types/components/footer/footer-category/footer-category.d.ts +16 -1
  659. package/dist/types/components/footer/footer-item/footer-item.d.ts +17 -1
  660. package/dist/types/components/footer/footer-legal/footer-legal.d.ts +15 -1
  661. package/dist/types/components/footer/footer-logo/footer-logo.d.ts +21 -2
  662. package/dist/types/components/footer/footer-social/footer-social.d.ts +20 -3
  663. package/dist/types/components/footer/footer.d.ts +39 -3
  664. package/dist/types/components/header/header-context.d.ts +1 -0
  665. package/dist/types/components/header/header-function/header-function.d.ts +24 -2
  666. package/dist/types/components/header/header-link/header-link.d.ts +22 -1
  667. package/dist/types/components/header/header-list/header-list.d.ts +16 -8
  668. package/dist/types/components/header/header-logo/header-logo.d.ts +20 -1
  669. package/dist/types/components/header/header.d.ts +47 -7
  670. package/dist/types/components/icon/icon.d.ts +44 -13
  671. package/dist/types/components/icon/icon.utils.d.ts +6 -0
  672. package/dist/types/components/input/input.d.ts +74 -15
  673. package/dist/types/components/item/item.d.ts +44 -6
  674. package/dist/types/components/link/link.d.ts +41 -9
  675. package/dist/types/components/list/list.d.ts +58 -8
  676. package/dist/types/components/loading/loading.d.ts +48 -8
  677. package/dist/types/components/magic-button/magic-button.d.ts +41 -3
  678. package/dist/types/components/menu/menu-group/menu-group.d.ts +19 -1
  679. package/dist/types/components/menu/menu-header/menu-header.d.ts +16 -1
  680. package/dist/types/components/menu/menu-info/menu-info.d.ts +14 -1
  681. package/dist/types/components/menu/menu-item/menu-item.d.ts +27 -3
  682. package/dist/types/components/menu/menu-link/menu-link.d.ts +17 -1
  683. package/dist/types/components/menu/menu-list/menu-list.d.ts +22 -4
  684. package/dist/types/components/menu/menu-logo/menu-logo.d.ts +14 -1
  685. package/dist/types/components/menu/menu-social/menu-social.d.ts +21 -2
  686. package/dist/types/components/menu/menu.d.ts +39 -6
  687. package/dist/types/components/menu/menu.utils.d.ts +2 -6
  688. package/dist/types/components/message/message.d.ts +38 -9
  689. package/dist/types/components/modal/modal.d.ts +40 -4
  690. package/dist/types/components/notification/notification-body/notification-body.d.ts +12 -3
  691. package/dist/types/components/notification/notification-header/notification-header.d.ts +12 -3
  692. package/dist/types/components/notification/notification-item/notification-item.d.ts +15 -3
  693. package/dist/types/components/notification/notification.d.ts +36 -5
  694. package/dist/types/components/pagination/pagination.d.ts +58 -20
  695. package/dist/types/components/radio/radio.d.ts +49 -4
  696. package/dist/types/components/radio-group/radio-group.d.ts +52 -10
  697. package/dist/types/components/scrim/scrim.d.ts +72 -11
  698. package/dist/types/components/scrim/scrim.utils.d.ts +2 -17
  699. package/dist/types/components/select/select-input/select-input.d.ts +22 -4
  700. package/dist/types/components/select/select-list/select-list.d.ts +51 -5
  701. package/dist/types/components/select/select-option/select-option.d.ts +31 -8
  702. package/dist/types/components/select/select.d.ts +152 -13
  703. package/dist/types/components/select/select.types.d.ts +5 -0
  704. package/dist/types/components/sign-in/sign-in.d.ts +32 -4
  705. package/dist/types/components/skip-link/skip-link-item/skip-link-item-alias.d.ts +15 -2
  706. package/dist/types/components/skip-link/skip-link-item/skip-link-item.d.ts +22 -1
  707. package/dist/types/components/skip-link/skip-link.d.ts +37 -3
  708. package/dist/types/components/slider/slider.d.ts +147 -21
  709. package/dist/types/components/slider/slider.types.d.ts +7 -2
  710. package/dist/types/components/slider/slider.utils.d.ts +27 -0
  711. package/dist/types/components/step/step-item/step-item.d.ts +15 -3
  712. package/dist/types/components/step/step.d.ts +47 -12
  713. package/dist/types/components/switch/switch.d.ts +39 -6
  714. package/dist/types/components/tab/tab-item/tab-item.d.ts +24 -4
  715. package/dist/types/components/tab/tab.d.ts +48 -11
  716. package/dist/types/components/table/table-body/table-body.d.ts +10 -6
  717. package/dist/types/components/table/table-cell/table-cell.d.ts +10 -6
  718. package/dist/types/components/table/table-header/table-header.d.ts +10 -6
  719. package/dist/types/components/table/table-header-cell/table-header-cell.d.ts +18 -6
  720. package/dist/types/components/table/table-row/table-row.d.ts +11 -6
  721. package/dist/types/components/table/table.d.ts +49 -11
  722. package/dist/types/components/tag/tag.d.ts +55 -7
  723. package/dist/types/components/textarea/textarea.d.ts +75 -5
  724. package/dist/types/components/textarea/textarea.types.d.ts +4 -0
  725. package/dist/types/components/tooltip/tooltip.d.ts +46 -8
  726. package/dist/types/components/upload/upload.d.ts +78 -10
  727. package/dist/types/components/wizard/wizard-panel/wizard-panel.d.ts +20 -2
  728. package/dist/types/components/wizard/wizard.d.ts +44 -7
  729. package/dist/types/components.d.ts +5827 -1354
  730. package/dist/types/shared/utils/floating-ui.d.ts +4 -0
  731. package/dist/types/shared/utils/focus.d.ts +14 -0
  732. package/dist/types/shared/utils/form.d.ts +8 -0
  733. package/dist/types/shared/utils/getRandom.d.ts +1 -0
  734. package/dist/types/shared/utils/id.d.ts +1 -1
  735. package/dist/types/shared/utils/index.d.ts +6 -1
  736. package/dist/types/shared/utils/motion.d.ts +14 -0
  737. package/dist/types/shared/utils/ownership.d.ts +33 -0
  738. package/dist/types/shared/utils/prop-warning.d.ts +7 -0
  739. package/dist/types/shared/utils/props.d.ts +38 -0
  740. package/dist/types/shared/utils/swipe.d.ts +5 -0
  741. package/dist/types/shared/utils/virtual-scroll.d.ts +25 -0
  742. package/dist/types/stencil-public-runtime.d.ts +73 -55
  743. package/dist/webcomponents/index.esm.js +1 -1
  744. package/dist/webcomponents/p-078bd760.entry.js +5 -0
  745. package/dist/webcomponents/p-07c2cdff.entry.js +5 -0
  746. package/dist/webcomponents/{p-7f7506f0.entry.js → p-09817344.entry.js} +1 -1
  747. package/dist/webcomponents/p-0b0cf355.entry.js +5 -0
  748. package/dist/webcomponents/p-0d2ca2f7.entry.js +5 -0
  749. package/dist/webcomponents/p-0d79ca44.entry.js +5 -0
  750. package/dist/webcomponents/p-0fe3c47b.entry.js +5 -0
  751. package/dist/webcomponents/p-116b53c9.entry.js +5 -0
  752. package/dist/webcomponents/p-1240dae7.entry.js +5 -0
  753. package/dist/webcomponents/p-14ff5865.entry.js +5 -0
  754. package/dist/webcomponents/p-15743a02.entry.js +5 -0
  755. package/dist/webcomponents/p-16cebf49.entry.js +5 -0
  756. package/dist/webcomponents/p-1884b9d3.entry.js +5 -0
  757. package/dist/webcomponents/p-19a38e20.entry.js +5 -0
  758. package/dist/webcomponents/p-1d36c8fa.entry.js +5 -0
  759. package/dist/webcomponents/p-1fa4b5b2.entry.js +5 -0
  760. package/dist/webcomponents/p-212c069b.entry.js +5 -0
  761. package/dist/webcomponents/p-23f37cd6.entry.js +5 -0
  762. package/dist/webcomponents/p-24502b63.entry.js +5 -0
  763. package/dist/webcomponents/p-27fb81f3.entry.js +5 -0
  764. package/dist/webcomponents/p-28844490.entry.js +5 -0
  765. package/dist/webcomponents/p-2b41bdcc.entry.js +5 -0
  766. package/dist/webcomponents/p-2cb1e09b.entry.js +5 -0
  767. package/dist/webcomponents/p-2fcda70b.entry.js +5 -0
  768. package/dist/webcomponents/p-3378300c.entry.js +5 -0
  769. package/dist/webcomponents/p-3ae9cf69.entry.js +5 -0
  770. package/dist/webcomponents/p-3b79cd49.entry.js +5 -0
  771. package/dist/webcomponents/p-3c1513ec.entry.js +5 -0
  772. package/dist/webcomponents/p-4118b878.entry.js +5 -0
  773. package/dist/webcomponents/p-4534a3c3.entry.js +5 -0
  774. package/dist/webcomponents/p-48abf568.entry.js +5 -0
  775. package/dist/webcomponents/p-4e5ea05c.entry.js +5 -0
  776. package/dist/webcomponents/p-513ee754.entry.js +5 -0
  777. package/dist/webcomponents/p-521a1076.entry.js +5 -0
  778. package/dist/webcomponents/p-59fc52c0.entry.js +5 -0
  779. package/dist/webcomponents/p-5a7c2031.entry.js +5 -0
  780. package/dist/webcomponents/p-5a9f4ea2.entry.js +5 -0
  781. package/dist/webcomponents/p-5f422a69.entry.js +5 -0
  782. package/dist/webcomponents/p-61977114.entry.js +5 -0
  783. package/dist/webcomponents/p-6850e98e.entry.js +5 -0
  784. package/dist/webcomponents/p-71853dfc.entry.js +5 -0
  785. package/dist/webcomponents/p-76d51654.entry.js +5 -0
  786. package/dist/webcomponents/p-77e242f3.entry.js +5 -0
  787. package/dist/webcomponents/p-7b849472.entry.js +5 -0
  788. package/dist/webcomponents/p-7dbfb875.entry.js +5 -0
  789. package/dist/webcomponents/p-7fa7f052.entry.js +5 -0
  790. package/dist/webcomponents/p-81c65747.entry.js +5 -0
  791. package/dist/webcomponents/p-82759002.entry.js +5 -0
  792. package/dist/webcomponents/p-91a5329f.entry.js +5 -0
  793. package/dist/webcomponents/p-94848046.entry.js +5 -0
  794. package/dist/webcomponents/p-966773a9.entry.js +5 -0
  795. package/dist/webcomponents/p-9abb5a53.entry.js +5 -0
  796. package/dist/webcomponents/p-9bf2e325.entry.js +5 -0
  797. package/dist/webcomponents/p-9c943b40.entry.js +5 -0
  798. package/dist/webcomponents/p-9ec3ca00.entry.js +5 -0
  799. package/dist/webcomponents/p-B0PbhaxL.js +5 -0
  800. package/dist/webcomponents/p-BEJGB0Nd.js +5 -0
  801. package/dist/{components/p-Dmfk7eEe.js → webcomponents/p-BJZC_NuV.js} +1 -1
  802. package/dist/webcomponents/p-BJtdabsr.js +5 -0
  803. package/dist/webcomponents/p-BeJxz5TQ.js +5 -0
  804. package/dist/webcomponents/p-BkWWrDEr.js +5 -0
  805. package/dist/webcomponents/p-BlGV-x0w.js +5 -0
  806. package/dist/webcomponents/{p-Bfm58jO6.js → p-BtRPYRvA.js} +1 -1
  807. package/dist/webcomponents/p-CDtFCbKp.js +5 -0
  808. package/dist/webcomponents/p-CNwZRgyL.js +5 -0
  809. package/dist/webcomponents/{p-DFN_so7I.js → p-CfuJQ1DY.js} +1 -1
  810. package/dist/webcomponents/p-ConyRdJe.js +7 -0
  811. package/dist/webcomponents/p-D9Zo6FlV.js +5 -0
  812. package/dist/webcomponents/{p-BhMVJQ4-.js → p-DV-iW9Aj.js} +1 -1
  813. package/dist/webcomponents/p-DWhzxlCx.js +5 -0
  814. package/dist/webcomponents/p-EbtQZm5s.js +5 -0
  815. package/dist/webcomponents/p-ad91f149.entry.js +5 -0
  816. package/dist/webcomponents/p-aeea1f17.entry.js +5 -0
  817. package/dist/webcomponents/p-b02a7218.entry.js +5 -0
  818. package/dist/webcomponents/p-b16590fc.entry.js +5 -0
  819. package/dist/webcomponents/{p-12286e73.entry.js → p-b55425b7.entry.js} +1 -1
  820. package/dist/webcomponents/p-c1dafd8d.entry.js +5 -0
  821. package/dist/webcomponents/p-c2ca0289.entry.js +5 -0
  822. package/dist/webcomponents/p-c8af334e.entry.js +5 -0
  823. package/dist/webcomponents/p-cac49c6a.entry.js +5 -0
  824. package/dist/webcomponents/p-cb9ebfbe.entry.js +5 -0
  825. package/dist/webcomponents/p-ce3d689c.entry.js +5 -0
  826. package/dist/webcomponents/p-d11f95a0.entry.js +5 -0
  827. package/dist/webcomponents/p-d5d2205c.entry.js +5 -0
  828. package/dist/webcomponents/p-dad03b49.entry.js +5 -0
  829. package/dist/webcomponents/p-db8e6322.entry.js +5 -0
  830. package/dist/webcomponents/p-dea8015f.entry.js +5 -0
  831. package/dist/webcomponents/p-e07e309d.entry.js +5 -0
  832. package/dist/webcomponents/p-e53d874b.entry.js +5 -0
  833. package/dist/webcomponents/p-e5540387.entry.js +5 -0
  834. package/dist/webcomponents/p-e94a52ac.entry.js +5 -0
  835. package/dist/webcomponents/p-e9be4d3f.entry.js +5 -0
  836. package/dist/webcomponents/p-e9db9381.entry.js +5 -0
  837. package/dist/webcomponents/p-edca5de1.entry.js +5 -0
  838. package/dist/webcomponents/p-ee5b9fc9.entry.js +5 -0
  839. package/dist/webcomponents/p-f4ef8c63.entry.js +5 -0
  840. package/dist/webcomponents/p-zlORkiHQ.js +5 -0
  841. package/dist/webcomponents/webcomponents.esm.js +1 -1
  842. package/package.json +18 -3
  843. package/dist/cjs/clamp-Co_hWptd.js +0 -25
  844. package/dist/cjs/id-CjRFMzf6.js +0 -20
  845. package/dist/cjs/props-CScmBvKd.js +0 -24
  846. package/dist/collection/pages/components/cookiebar/index.js +0 -26
  847. package/dist/collection/pages/components/link/index.js +0 -29
  848. package/dist/collection/pages/components/pagination/index.js +0 -12
  849. package/dist/collection/pages/components/slider/index.js +0 -18
  850. package/dist/components/p-6OdfnwnK.js +0 -5
  851. package/dist/components/p-AmOh1cks.js +0 -5
  852. package/dist/components/p-B4ylcipx.js +0 -5
  853. package/dist/components/p-BCv4PCOx.js +0 -5
  854. package/dist/components/p-BLOyd_iF.js +0 -5
  855. package/dist/components/p-BODem6tr.js +0 -5
  856. package/dist/components/p-Bb-nLtTG.js +0 -5
  857. package/dist/components/p-BeFK-82z.js +0 -5
  858. package/dist/components/p-BkS6ujyf.js +0 -5
  859. package/dist/components/p-BloE-KAN.js +0 -5
  860. package/dist/components/p-BoSc_kmY.js +0 -5
  861. package/dist/components/p-BrH3r7eL.js +0 -5
  862. package/dist/components/p-BsZ0Ny88.js +0 -5
  863. package/dist/components/p-ByHVf7zy.js +0 -5
  864. package/dist/components/p-CdDwqbBv.js +0 -5
  865. package/dist/components/p-CdF-gmk1.js +0 -5
  866. package/dist/components/p-CfyjGPGI.js +0 -5
  867. package/dist/components/p-CjF7pBVQ.js +0 -5
  868. package/dist/components/p-ClqtllDH.js +0 -5
  869. package/dist/components/p-CqW2Yh34.js +0 -5
  870. package/dist/components/p-DIK54tTj.js +0 -5
  871. package/dist/components/p-DLE5ioJN.js +0 -5
  872. package/dist/components/p-DQRSHR-D.js +0 -5
  873. package/dist/components/p-DRVMm1Py.js +0 -5
  874. package/dist/components/p-DRnCpVrL.js +0 -5
  875. package/dist/components/p-DVdlaP7z.js +0 -5
  876. package/dist/components/p-DeeF6ok0.js +0 -5
  877. package/dist/components/p-Dim2PnUm.js +0 -5
  878. package/dist/components/p-Dk8rfQjL.js +0 -5
  879. package/dist/components/p-DkmEpoef.js +0 -5
  880. package/dist/components/p-DwfAYaEv.js +0 -5
  881. package/dist/components/p-DxZJrIyL.js +0 -5
  882. package/dist/components/p-P2Z_MmH6.js +0 -5
  883. package/dist/components/p-Xa0Mj4pP.js +0 -5
  884. package/dist/components/p-_vsQvdxD.js +0 -5
  885. package/dist/components/p-aNjo4Alx.js +0 -5
  886. package/dist/components/p-gvnfuTjd.js +0 -5
  887. package/dist/components/p-rB-s1M3Q.js +0 -5
  888. package/dist/esm/clamp-gvnfuTjd.js +0 -23
  889. package/dist/esm/id-BkS6ujyf.js +0 -18
  890. package/dist/esm/props-DRVMm1Py.js +0 -22
  891. package/dist/webcomponents/p-00cc31f9.entry.js +0 -5
  892. package/dist/webcomponents/p-026475bd.entry.js +0 -5
  893. package/dist/webcomponents/p-0291ab28.entry.js +0 -5
  894. package/dist/webcomponents/p-03e5a7dc.entry.js +0 -5
  895. package/dist/webcomponents/p-060df8ee.entry.js +0 -5
  896. package/dist/webcomponents/p-09fce2a5.entry.js +0 -5
  897. package/dist/webcomponents/p-1002bbff.entry.js +0 -5
  898. package/dist/webcomponents/p-1124de33.entry.js +0 -5
  899. package/dist/webcomponents/p-12e97d80.entry.js +0 -5
  900. package/dist/webcomponents/p-1580beee.entry.js +0 -5
  901. package/dist/webcomponents/p-1b19b191.entry.js +0 -5
  902. package/dist/webcomponents/p-2baf353b.entry.js +0 -5
  903. package/dist/webcomponents/p-2eb9a42c.entry.js +0 -5
  904. package/dist/webcomponents/p-30c82805.entry.js +0 -5
  905. package/dist/webcomponents/p-31bd1c74.entry.js +0 -5
  906. package/dist/webcomponents/p-31db2313.entry.js +0 -5
  907. package/dist/webcomponents/p-33a3dc63.entry.js +0 -5
  908. package/dist/webcomponents/p-3889c51f.entry.js +0 -5
  909. package/dist/webcomponents/p-3f2c179a.entry.js +0 -5
  910. package/dist/webcomponents/p-470eb770.entry.js +0 -5
  911. package/dist/webcomponents/p-4ae387ae.entry.js +0 -5
  912. package/dist/webcomponents/p-4e65df84.entry.js +0 -5
  913. package/dist/webcomponents/p-51a62876.entry.js +0 -5
  914. package/dist/webcomponents/p-5860b96b.entry.js +0 -5
  915. package/dist/webcomponents/p-5b9c01e9.entry.js +0 -5
  916. package/dist/webcomponents/p-5df2f1dd.entry.js +0 -5
  917. package/dist/webcomponents/p-5f3f7b3f.entry.js +0 -5
  918. package/dist/webcomponents/p-5f6afb79.entry.js +0 -5
  919. package/dist/webcomponents/p-5f9c28a7.entry.js +0 -5
  920. package/dist/webcomponents/p-62511921.entry.js +0 -5
  921. package/dist/webcomponents/p-63b52947.entry.js +0 -5
  922. package/dist/webcomponents/p-67a8e0b7.entry.js +0 -5
  923. package/dist/webcomponents/p-6OdfnwnK.js +0 -5
  924. package/dist/webcomponents/p-7b2a5fec.entry.js +0 -5
  925. package/dist/webcomponents/p-7f95e2f5.entry.js +0 -5
  926. package/dist/webcomponents/p-8128833c.entry.js +0 -5
  927. package/dist/webcomponents/p-8200ccb1.entry.js +0 -5
  928. package/dist/webcomponents/p-82b100fd.entry.js +0 -5
  929. package/dist/webcomponents/p-8806df15.entry.js +0 -5
  930. package/dist/webcomponents/p-881eb81a.entry.js +0 -5
  931. package/dist/webcomponents/p-8bd3d541.entry.js +0 -5
  932. package/dist/webcomponents/p-90648343.entry.js +0 -5
  933. package/dist/webcomponents/p-9100a5f7.entry.js +0 -5
  934. package/dist/webcomponents/p-91313d77.entry.js +0 -5
  935. package/dist/webcomponents/p-946b2ac0.entry.js +0 -5
  936. package/dist/webcomponents/p-98e7ccb9.entry.js +0 -5
  937. package/dist/webcomponents/p-99f2bddb.entry.js +0 -5
  938. package/dist/webcomponents/p-9adbdb0a.entry.js +0 -5
  939. package/dist/webcomponents/p-9c260049.entry.js +0 -5
  940. package/dist/webcomponents/p-9ed51017.entry.js +0 -5
  941. package/dist/webcomponents/p-BkS6ujyf.js +0 -5
  942. package/dist/webcomponents/p-C2RBydfd.js +0 -6
  943. package/dist/webcomponents/p-CO5cOQQU.js +0 -5
  944. package/dist/webcomponents/p-D3tVP32U.js +0 -5
  945. package/dist/webcomponents/p-DIK54tTj.js +0 -5
  946. package/dist/webcomponents/p-DRVMm1Py.js +0 -5
  947. package/dist/webcomponents/p-DxZJrIyL.js +0 -5
  948. package/dist/webcomponents/p-a0b299dd.entry.js +0 -5
  949. package/dist/webcomponents/p-a2c5fad0.entry.js +0 -5
  950. package/dist/webcomponents/p-a3e044d7.entry.js +0 -5
  951. package/dist/webcomponents/p-a9f23aa7.entry.js +0 -5
  952. package/dist/webcomponents/p-a9f2fcbc.entry.js +0 -5
  953. package/dist/webcomponents/p-b6c68136.entry.js +0 -5
  954. package/dist/webcomponents/p-b6e9b8d1.entry.js +0 -5
  955. package/dist/webcomponents/p-c333eac6.entry.js +0 -5
  956. package/dist/webcomponents/p-c3732fd6.entry.js +0 -5
  957. package/dist/webcomponents/p-c458ed0e.entry.js +0 -5
  958. package/dist/webcomponents/p-c91000ff.entry.js +0 -5
  959. package/dist/webcomponents/p-c9c6ab2d.entry.js +0 -5
  960. package/dist/webcomponents/p-cd2550d6.entry.js +0 -5
  961. package/dist/webcomponents/p-cf42613f.entry.js +0 -5
  962. package/dist/webcomponents/p-d0b0b420.entry.js +0 -5
  963. package/dist/webcomponents/p-d1b32ee8.entry.js +0 -5
  964. package/dist/webcomponents/p-db65b083.entry.js +0 -5
  965. package/dist/webcomponents/p-de7c101d.entry.js +0 -5
  966. package/dist/webcomponents/p-dfb77dd0.entry.js +0 -5
  967. package/dist/webcomponents/p-e258da78.entry.js +0 -5
  968. package/dist/webcomponents/p-e31ddd42.entry.js +0 -5
  969. package/dist/webcomponents/p-e8d82227.entry.js +0 -5
  970. package/dist/webcomponents/p-e988cf1d.entry.js +0 -5
  971. package/dist/webcomponents/p-ed9122a1.entry.js +0 -5
  972. package/dist/webcomponents/p-ee347d2e.entry.js +0 -5
  973. package/dist/webcomponents/p-f1c01d52.entry.js +0 -5
  974. package/dist/webcomponents/p-f5baf8be.entry.js +0 -5
  975. package/dist/webcomponents/p-fb593739.entry.js +0 -5
  976. package/dist/webcomponents/p-fff9acd4.entry.js +0 -5
  977. package/dist/webcomponents/p-gvnfuTjd.js +0 -5
@@ -4,10 +4,77 @@ const CLEAR_COMPONENTS_FILTER = document.getElementById('clear-components-filter
4
4
 
5
5
  let renderedFilesContent = {};
6
6
  let currentLoadedPath = null;
7
+ let pageLoadGeneration = 0;
8
+ const activeExampleCleanups = new Set();
7
9
  const markdownParser = window.marked;
8
- const DEV_SERVER_CONNECTOR_IFRAME_RE =
9
- /<iframe\b[^>]*title=["']Stencil Dev Server Connector[^"']*["'][\s\S]*?<\/iframe>/gi;
10
10
  let lzStringPromise;
11
+ const MAX_PLAYGROUND_DRAFT_SIZE = 512 * 1024;
12
+ const DEV_VIEWPORTS = [
13
+ { id: 'desktop', label: 'Desktop (100%)', icon: 'fas fa-desktop', mode: 'web', width: null, height: null },
14
+ { id: 'tablet', label: 'Tablet - 768px', icon: 'fas fa-tablet-alt', mode: 'web', width: 768, height: 600 },
15
+ { id: 'ios', label: 'iPhone (iOS) - 390x844', icon: 'fab fa-apple', mode: 'ios', width: 390, height: 844 },
16
+ { id: 'android', label: 'Android - 360x800', icon: 'fab fa-android', mode: 'android', width: 360, height: 800 },
17
+ ];
18
+ const DEV_PREVIEW_MIN_WIDTH = 200;
19
+ const DEV_PREVIEW_MIN_HEIGHT = 180;
20
+ const DEV_PREVIEW_RESIZE_STEP = 16;
21
+
22
+ function createPreviewResizeHandle(axis) {
23
+ const isWidthHandle = axis === 'vertical';
24
+ const handle = document.createElement('div');
25
+ handle.className = `wbc-example-preview-resize-handle wbc-example-preview-resize-handle--${axis}`;
26
+ handle.setAttribute('role', 'separator');
27
+ handle.setAttribute('tabindex', '0');
28
+ handle.setAttribute(
29
+ 'aria-label',
30
+ isWidthHandle ? 'Redimensionar largura do preview' : 'Redimensionar altura do preview',
31
+ );
32
+ handle.setAttribute('aria-orientation', axis);
33
+ const line = document.createElement('span');
34
+ line.className = 'wbc-example-preview-resize-handle__line';
35
+ handle.appendChild(line);
36
+ return handle;
37
+ }
38
+
39
+ function getPreviewResizeDelta(key, decreaseKey, increaseKey) {
40
+ if (key === decreaseKey) return -DEV_PREVIEW_RESIZE_STEP;
41
+ if (key === increaseKey) return DEV_PREVIEW_RESIZE_STEP;
42
+ return 0;
43
+ }
44
+
45
+ function getPlaygroundDraftKey(path, file) {
46
+ return `wbc-playground-draft:${path}/${file}`;
47
+ }
48
+
49
+ function readPlaygroundDraft(path, file) {
50
+ try {
51
+ const raw = window.localStorage.getItem(getPlaygroundDraftKey(path, file));
52
+ if (!raw || raw.length > MAX_PLAYGROUND_DRAFT_SIZE) return null;
53
+ const draft = JSON.parse(raw);
54
+ if (typeof draft?.html !== 'string') return null;
55
+ return draft;
56
+ } catch {
57
+ return null;
58
+ }
59
+ }
60
+
61
+ function writePlaygroundDraft(path, file, draft) {
62
+ try {
63
+ const serialized = JSON.stringify({ ...draft, updatedAt: Date.now() });
64
+ if (serialized.length > MAX_PLAYGROUND_DRAFT_SIZE) return false;
65
+ window.localStorage.setItem(getPlaygroundDraftKey(path, file), serialized);
66
+ return true;
67
+ } catch {
68
+ return false;
69
+ }
70
+ }
71
+
72
+ function getScrollBehavior() {
73
+ const prefersReducedMotion =
74
+ (typeof document !== 'undefined' && document.documentElement.dataset.wbcReducedMotion === 'true') ||
75
+ (typeof window.matchMedia === 'function' && window.matchMedia('(prefers-reduced-motion: reduce)').matches);
76
+ return prefersReducedMotion ? 'auto' : 'smooth';
77
+ }
11
78
 
12
79
  function loadLzString() {
13
80
  if (window.LZString) return Promise.resolve(window.LZString);
@@ -23,6 +90,13 @@ function loadLzString() {
23
90
  return lzStringPromise;
24
91
  }
25
92
 
93
+ function cleanupExamples() {
94
+ activeExampleCleanups.forEach((cleanup) => {
95
+ cleanup();
96
+ });
97
+ activeExampleCleanups.clear();
98
+ }
99
+
26
100
  // Decode shared state from URL parameters on initialization
27
101
  (() => {
28
102
  const params = new URLSearchParams(window.location.search);
@@ -53,313 +127,7 @@ function getBaseUrl() {
53
127
  return baseUrl === '' ? '' : baseUrl;
54
128
  }
55
129
 
56
- function renderExamplePreview(previewElement, source, edgeToEdge = false) {
57
- const frame = previewElement.querySelector('iframe');
58
- if (!frame) return;
59
-
60
- const baseUrl = getBaseUrl();
61
- const componentBundleUrl = new URL(`${baseUrl}/build/webcomponents.esm.js`, window.location.href);
62
- componentBundleUrl.searchParams.set('preview-version', String(Date.now()));
63
- const componentBundle = componentBundleUrl.href;
64
- const frameSource = stripDevServerConnector(source);
65
-
66
- frame.srcdoc = `<!doctype html>
67
- <html lang="pt-BR">
68
- <head>
69
- <meta charset="UTF-8">
70
- <meta name="viewport" content="width=device-width, initial-scale=1">
71
- <base href="${window.location.href}">
72
- <link rel="stylesheet" href="${new URL(`${baseUrl}/assets/core.min.css`, window.location.href).href}">
73
- <link rel="stylesheet" href="${new URL(`${baseUrl}/assets/fonts/rawline/400.css`, window.location.href).href}">
74
- <link rel="stylesheet" href="${new URL(`${baseUrl}/assets/fonts/raleway/wght.css`, window.location.href).href}">
75
- <link rel="stylesheet" href="${new URL(`${baseUrl}/assets/fonts/fontawesome/css/all.min.css`, window.location.href).href}">
76
- <style>
77
- * { font-family: Rawline, Raleway, sans-serif; }
78
- html, body { margin: 0; min-height: 1px; overflow: visible; }
79
- body { box-sizing: border-box; padding: 24px 16px; }
80
- body.wbc-preview-edge-to-edge { padding: 0; }
81
- br-cookiebar, br-scrim { inset: 0; position: absolute; pointer-events: none; z-index: 1000; }
82
- br-scrim { --scrim-display-mode: parent; }
83
- </style>
84
- </head>
85
- <body${edgeToEdge ? ' class="wbc-preview-edge-to-edge"' : ''}><main data-wbc-preview-content>${frameSource}</main>
86
- <script type="module" src="${componentBundle}"></script>
87
- <script>
88
- (() => {
89
- const overlayContentSelector =
90
- '[part="open-panel"], [part="default-panel"], [part="body"], .cookiebar-body, .content, .br-modal';
91
- const getOverlayHeight = (overlay) => {
92
- const measuredHeight = Array.from(overlay.shadowRoot?.querySelectorAll(overlayContentSelector) || []).reduce(
93
- (height, element) =>
94
- Math.max(height, element.scrollHeight, element.clientHeight, element.getBoundingClientRect().height),
95
- 0,
96
- );
97
- if (measuredHeight > 0) return measuredHeight;
98
-
99
- const modal = overlay.matches('br-scrim') ? overlay.querySelector('br-modal') : overlay;
100
- return modal?.shadowRoot?.querySelector('.br-modal')?.getBoundingClientRect().height || 0;
101
- };
102
- const getElementsIncludingShadowRoots = (root = document) => {
103
- const elements = [];
104
- const visit = (tree) => {
105
- tree.querySelectorAll('*').forEach((element) => {
106
- elements.push(element);
107
- if (element.shadowRoot) visit(element.shadowRoot);
108
- });
109
- };
110
- visit(root);
111
- return elements;
112
- };
113
- const getFloatingHeight = () => {
114
- const bodyStyle = getComputedStyle(document.body);
115
- const bottomPadding = parseFloat(bodyStyle.paddingBottom) || 0;
116
- return getElementsIncludingShadowRoots().reduce((height, element) => {
117
- if (element.matches('br-cookiebar, br-scrim, br-modal')) return height;
118
- const style = getComputedStyle(element);
119
- if (style.position !== 'absolute' && style.position !== 'fixed') return height;
120
- if (style.display === 'none' || style.visibility === 'hidden') return height;
121
- return Math.max(height, element.getBoundingClientRect().bottom + bottomPadding);
122
- }, 0);
123
- };
124
- const sendHeight = () => {
125
- const body = document.body;
126
- const bodyStyle = getComputedStyle(body);
127
- const overlayHeight = Array.from(document.querySelectorAll('br-cookiebar, br-scrim, br-modal')).reduce(
128
- (height, overlay) => Math.max(height, getOverlayHeight(overlay)),
129
- 0,
130
- );
131
- const verticalPadding = parseFloat(bodyStyle.paddingTop) + parseFloat(bodyStyle.paddingBottom);
132
- const height = Math.ceil(
133
- Math.max(
134
- body.scrollHeight,
135
- body.offsetHeight,
136
- body.getBoundingClientRect().height,
137
- overlayHeight + verticalPadding,
138
- getFloatingHeight(),
139
- ),
140
- );
141
- parent.postMessage({ type: 'wbc-preview-height', height }, '*');
142
- };
143
- document.querySelectorAll('br-cookiebar, br-scrim').forEach((overlay) => {
144
- overlay.setAttribute('data-wbc-preview-contained', '');
145
- if (overlay.matches('br-scrim')) overlay.setAttribute('display-mode', 'parent');
146
- });
147
- const serialize = (value, seen = new WeakSet()) => {
148
- if (value instanceof Element) return '<' + value.localName + '>';
149
- if (value instanceof Event) return { type: value.type };
150
- if (value && typeof value === 'object') {
151
- if (seen.has(value)) return '[Circular]';
152
- seen.add(value);
153
- if (Array.isArray(value)) return value.map((item) => serialize(item, seen));
154
- return Object.fromEntries(Object.entries(value).map(([key, item]) => [key, serialize(item, seen)]));
155
- }
156
- return value;
157
- };
158
- const sendEvent = (event, dispatchedBy = event.target) => {
159
- const target = dispatchedBy instanceof Element ? dispatchedBy : dispatchedBy?.host instanceof Element ? dispatchedBy.host : null;
160
- parent.postMessage({
161
- type: 'wbc-preview-event',
162
- eventType: event.type,
163
- custom: event instanceof CustomEvent,
164
- detail: event instanceof CustomEvent ? serialize(event.detail) : undefined,
165
- target: target ? target.localName + (target.id ? '#' + target.id : '') : 'window',
166
- }, '*');
167
- };
168
- ['change', 'click', 'input', 'submit'].forEach((name) => document.addEventListener(name, sendEvent, true));
169
- document.addEventListener('brInternalEvent', sendEvent, true);
170
- const originalDispatchEvent = EventTarget.prototype.dispatchEvent;
171
- EventTarget.prototype.dispatchEvent = function dispatchEvent(event) {
172
- if (event instanceof CustomEvent) sendEvent(event, this);
173
- return originalDispatchEvent.call(this, event);
174
- };
175
- let heightFrame = 0;
176
- const scheduleHeight = () => {
177
- cancelAnimationFrame(heightFrame);
178
- heightFrame = requestAnimationFrame(sendHeight);
179
- };
180
- const resizeObserver = new ResizeObserver(scheduleHeight);
181
- const observeOverlayContent = () => {
182
- document.querySelectorAll('br-cookiebar, br-scrim, br-modal').forEach((overlay) => {
183
- overlay.shadowRoot?.querySelectorAll(overlayContentSelector).forEach((element) => {
184
- resizeObserver.observe(element);
185
- });
186
- });
187
- getElementsIncludingShadowRoots().forEach((element) => {
188
- const position = getComputedStyle(element).position;
189
- if (position === 'absolute' || position === 'fixed') resizeObserver.observe(element);
190
- });
191
- };
192
- resizeObserver.observe(document.documentElement);
193
- resizeObserver.observe(document.body);
194
- new MutationObserver(() =>
195
- requestAnimationFrame(() => {
196
- observeOverlayContent();
197
- scheduleHeight();
198
- }),
199
- ).observe(document.body, { attributes: true, childList: true, subtree: true });
200
- Promise.all(
201
- [...document.querySelectorAll('*')]
202
- .map((element) => element.localName)
203
- .filter((tag, index, tags) => tag.includes('-') && tags.indexOf(tag) === index)
204
- .map((tag) => customElements.whenDefined(tag)),
205
- ).then(() =>
206
- requestAnimationFrame(() =>
207
- requestAnimationFrame(() => {
208
- observeOverlayContent();
209
- scheduleHeight();
210
- }),
211
- ),
212
- );
213
- addEventListener('load', scheduleHeight);
214
- scheduleHeight();
215
- })();
216
- </script>
217
- </body>
218
- </html>`;
219
- }
220
-
221
- function stripDevServerConnector(source) {
222
- return String(source || '')
223
- .replace(DEV_SERVER_CONNECTOR_IFRAME_RE, '')
224
- .trim();
225
- }
226
-
227
- function getFrameworkCode(source, framework) {
228
- const html = String(source || '').trim();
229
- const components = Array.from(html.matchAll(/<\/?(br-[a-z0-9-]+)/gi), (match) => match[1]);
230
- const imports = [...new Set(components)].map((tag) =>
231
- tag
232
- .split('-')
233
- .map((part) => part.charAt(0).toUpperCase() + part.slice(1))
234
- .join(''),
235
- );
236
- const importList = imports.length > 0 ? imports.join(', ') : 'BrButton';
237
- const pascalMarkup = html.replace(/(<\/?)(br-[a-z0-9-]+)/gi, (_match, prefix, tag) => {
238
- return `${prefix}${tag
239
- .split('-')
240
- .map((part) => part.charAt(0).toUpperCase() + part.slice(1))
241
- .join('')}`;
242
- });
243
-
244
- if (framework === 'javascript') {
245
- return `import { ${importList} } from '@govbr-ds/webcomponents';\n\nconst example = document.querySelector('${components[0] || 'br-button'}');\n\n// Use o exemplo renderizado para adicionar comportamento com JavaScript.\nconsole.log(example);`;
246
- }
247
- if (framework === 'css') {
248
- return `/* Customize os componentes usando CSS Parts */
249
- /* Exemplo:
250
- br-${String(location.pathname).split('/').filter(Boolean).pop() || 'component'}::part(container) {
251
- background-color: #f8f9fa;
252
- }
253
- */`;
254
- }
255
- if (framework === 'angular') {
256
- return `import { Component } from '@angular/core';\nimport { ${importList} } from '@govbr-ds/webcomponents-angular/standalone';\n\n@Component({\n selector: 'app-root',\n standalone: true,\n imports: [${importList}],\n template: \`${html.replace(/`/g, '\\`')}\`,\n})\nexport class AppComponent {}`;
257
- }
258
- if (framework === 'react') {
259
- return `import { ${importList} } from '@govbr-ds/webcomponents-react';\n\nexport default function App() {\n return (\n <>\n ${pascalMarkup.replace(/\n/g, '\n ')}\n </>\n );\n}`;
260
- }
261
- return `<script setup lang="ts">\nimport { ${importList} } from '@govbr-ds/webcomponents-vue';\n</script>\n\n<template>\n ${pascalMarkup.replace(/\n/g, '\n ')}\n</template>`;
262
- }
263
-
264
- function getFrameworkFiles(source, framework) {
265
- if (framework !== 'angular') return null;
266
-
267
- const html = String(source || '').trim();
268
- const components = Array.from(html.matchAll(/<\/?(br-[a-z0-9-]+)/gi), (match) => match[1]);
269
- const imports = [...new Set(components)].map((tag) =>
270
- tag
271
- .split('-')
272
- .map((part) => part.charAt(0).toUpperCase() + part.slice(1))
273
- .join(''),
274
- );
275
- const importList = imports.length > 0 ? imports.join(', ') : 'BrButton';
276
-
277
- return [
278
- {
279
- filename: 'app.component.ts',
280
- language: 'typescript',
281
- code: `import { Component } from '@angular/core'\nimport { ${importList} } from '@govbr-ds/webcomponents-angular/standalone'\n\n@Component({\n selector: 'app-root',\n standalone: true,\n imports: [${importList}],\n templateUrl: './app.component.html',\n})\nexport class AppComponent {}`,
282
- },
283
- { filename: 'app.component.html', language: 'html', code: html },
284
- ];
285
- }
286
-
287
- function createReadOnlyFrameworkTab(label, icon, tabId, source, framework) {
288
- const tab = document.createElement('br-tab-item');
289
- tab.setAttribute('label', label);
290
- tab.setAttribute('icon', icon);
291
- tab.setAttribute('icon-only', 'true');
292
- tab.setAttribute('title', label);
293
- tab.setAttribute('tab-item-id', tabId);
294
- tab.dataset.framework = framework;
295
-
296
- const files = getFrameworkFiles(source, framework);
297
- tab._frameworkFiles = files;
298
-
299
- if (files?.length > 1) {
300
- const fileTabs = document.createElement('div');
301
- fileTabs.className = 'wbc-framework-file-tabs';
302
- fileTabs.setAttribute('role', 'tablist');
303
- files.forEach((file, index) => {
304
- const fileTab = document.createElement('button');
305
- fileTab.className = `wbc-framework-file-tab${index === 0 ? ' is-active' : ''}`;
306
- fileTab.type = 'button';
307
- fileTab.dataset.filename = file.filename;
308
- fileTab.setAttribute('aria-selected', String(index === 0));
309
- fileTab.setAttribute('role', 'tab');
310
- fileTab.textContent = file.filename;
311
- fileTabs.appendChild(fileTab);
312
- });
313
- tab.appendChild(fileTabs);
314
- }
315
-
316
- const code = document.createElement('pre');
317
- code.className = 'wbc-framework-code';
318
- code.dataset.framework = framework;
319
- code.dataset.filename = files?.[0]?.filename || '';
320
- code.textContent = files?.[0]?.code || getFrameworkCode(source, framework);
321
- tab.appendChild(code);
322
- return tab;
323
- }
324
-
325
- async function getPreviewAxeContext(previewFrame) {
326
- const previewDocument = previewFrame.contentDocument;
327
- const previewWindow = previewFrame.contentWindow;
328
- if (!previewDocument?.body || !previewWindow) {
329
- throw new Error('O conteúdo do preview ainda não está disponível.');
330
- }
331
-
332
- if (!previewWindow.axe) {
333
- const axeScriptUrl = new URL(`${getBaseUrl()}/assets/axe-core.min.js`, window.location.href).href;
334
-
335
- const response = await fetch(axeScriptUrl);
336
- if (!response.ok) throw new Error('Não foi possível carregar o Axe-Core no preview.');
337
-
338
- const axeScript = previewDocument.createElement('script');
339
- axeScript.textContent = await response.text();
340
- previewDocument.head.appendChild(axeScript);
341
- }
342
-
343
- const previewContent = previewDocument.querySelector('[data-wbc-preview-content]');
344
- if (!previewContent) throw new Error('Não foi possível localizar o conteúdo do exemplo.');
345
-
346
- return { axe: previewWindow.axe, previewContent };
347
- }
348
-
349
- function getExampleHash(file) {
350
- return `#${encodeURIComponent(file)}`;
351
- }
352
-
353
- function getRequestedExampleFile() {
354
- if (!window.location.hash) return null;
355
- try {
356
- return decodeURIComponent(window.location.hash.slice(1));
357
- } catch {
358
- return window.location.hash.slice(1);
359
- }
360
- }
361
-
362
- function createExampleElement(path, file, text, isExpanded = false, onOpen) {
130
+ function createExampleElement(path, file, text, presets = [], defaultPreset = '', exampleLabel = '') {
363
131
  text = stripDevServerConnector(text);
364
132
  const contentDiv = document.createElement('br-item');
365
133
  contentDiv.classList.add('file', 'wbc-example');
@@ -367,54 +135,84 @@ function createExampleElement(path, file, text, isExpanded = false, onOpen) {
367
135
  contentDiv.dataset.exampleFile = file;
368
136
  const controlsScope = `wbc-example-${path}-${file}`.replace(/[^a-zA-Z0-9_-]/g, '-');
369
137
  contentDiv.dataset.controlsScope = controlsScope;
138
+ const previewChannelId = `${controlsScope}-preview`;
370
139
 
371
- const dropdown = document.createElement('br-dropdown');
372
- dropdown.className = 'wbc-example-dropdown';
373
- if (isExpanded) dropdown.setAttribute('is-open', '');
140
+ const exampleAbortController = new AbortController();
374
141
  let initializeExample;
375
142
  let isInitialized = false;
376
143
 
377
144
  const preview = document.createElement('div');
378
145
  preview.className = 'wbc-example-preview';
146
+ const previewViewport = document.createElement('div');
147
+ previewViewport.className = 'wbc-example-preview-viewport';
379
148
  let previewFrame;
149
+ const previewWidthResizeHandle = createPreviewResizeHandle('vertical');
150
+ const previewHeightResizeHandle = createPreviewResizeHandle('horizontal');
151
+ let previewResizeState = null;
152
+ let hasManualPreviewHeight = false;
153
+ let activeViewport = DEV_VIEWPORTS[0];
154
+ let darkThemeEnabled = false;
155
+ let reducedMotionEnabled =
156
+ typeof window.matchMedia === 'function' && window.matchMedia('(prefers-reduced-motion: reduce)').matches;
380
157
 
381
158
  // --- EDITOR CONTAINER ---
382
159
  const editorContainer = document.createElement('div');
383
160
  editorContainer.className = 'wbc-example-editor-container';
384
161
 
162
+ // Ids nativos das abas, com o escopo do exemplo para não duplicar ids entre exemplos da página.
163
+ const tabIds = Object.fromEntries(
164
+ ['code', 'events', 'controls', 'a11y', 'javascript', 'css', 'angular', 'react', 'vue'].map((name) => [
165
+ name,
166
+ `${controlsScope}-${name}-tab`,
167
+ ]),
168
+ );
385
169
  const tabComponent = document.createElement('br-tab');
386
170
  tabComponent.setAttribute('density', 'small');
387
- tabComponent.setAttribute('active-tab-id', 'code-tab');
171
+ // Ícones por classe (Font Awesome) em light DOM, pelo slot `icon-{id}` do br-tab.
172
+ const setTabIcon = (tabItem, iconClass) => {
173
+ const icon = document.createElement('i');
174
+ icon.slot = `icon-${tabItem.id}`;
175
+ icon.className = iconClass;
176
+ icon.setAttribute('aria-hidden', 'true');
177
+ tabComponent.appendChild(icon);
178
+ };
179
+ tabComponent.setAttribute('active-tab-id', tabIds.code);
180
+ tabComponent.setAttribute('data-playground-badges', '');
388
181
 
389
182
  const codeTabItem = document.createElement('br-tab-item');
390
183
  codeTabItem.setAttribute('label', 'HTML');
391
- codeTabItem.setAttribute('icon', 'fab fa-html5');
392
184
  codeTabItem.setAttribute('icon-only', 'true');
393
- codeTabItem.setAttribute('title', 'HTML');
394
- codeTabItem.setAttribute('tab-item-id', 'code-tab');
185
+ codeTabItem.setAttribute('title', 'Editor HTML');
186
+ codeTabItem.id = tabIds.code;
395
187
  codeTabItem.setAttribute('active', 'true');
396
- codeTabItem.setAttribute('is-active', 'true');
397
188
 
398
189
  const eventsTabItem = document.createElement('br-tab-item');
399
190
  eventsTabItem.setAttribute('label', 'Console');
400
- eventsTabItem.setAttribute('icon', 'fas fa-terminal');
401
191
  eventsTabItem.setAttribute('icon-only', 'true');
402
- eventsTabItem.setAttribute('title', 'Console');
403
- eventsTabItem.setAttribute('tab-item-id', 'events-tab');
192
+ eventsTabItem.setAttribute('title', 'Console: eventos e mensagens de runtime');
193
+ eventsTabItem.id = tabIds.events;
404
194
 
405
195
  const controlsTabItem = document.createElement('br-tab-item');
406
196
  controlsTabItem.setAttribute('label', 'Controles');
407
- controlsTabItem.setAttribute('icon', 'fas fa-sliders-h');
408
197
  controlsTabItem.setAttribute('icon-only', 'true');
409
- controlsTabItem.setAttribute('title', 'Controles');
410
- controlsTabItem.setAttribute('tab-item-id', 'controls-tab');
411
-
412
- const javascriptTabItem = createReadOnlyFrameworkTab('JS', 'fab fa-js', 'javascript-tab', text, 'javascript');
413
- const cssTabItem = createReadOnlyFrameworkTab('CSS', 'fab fa-css3-alt', 'css-tab', text, 'css');
414
- const angularTabItem = createReadOnlyFrameworkTab('Angular', 'fab fa-angular', 'angular-tab', text, 'angular');
415
- const reactTabItem = createReadOnlyFrameworkTab('React', 'fab fa-react', 'react-tab', text, 'react');
416
- const vueTabItem = createReadOnlyFrameworkTab('Vue', 'fab fa-vuejs', 'vue-tab', text, 'vue');
198
+ controlsTabItem.setAttribute('title', 'Controles do componente');
199
+ controlsTabItem.id = tabIds.controls;
200
+
201
+ const javascriptTabItem = createFrameworkTab('JS', 'fab fa-js', tabIds.javascript, text, 'javascript', {
202
+ editable: true,
203
+ });
204
+ const cssTabItem = createFrameworkTab('CSS', 'fab fa-css3-alt', tabIds.css, text, 'css', { editable: true });
205
+ const angularTabItem = createFrameworkTab('Angular', 'fab fa-angular', tabIds.angular, text, 'angular');
206
+ const reactTabItem = createFrameworkTab('React', 'fab fa-react', tabIds.react, text, 'react');
207
+ const vueTabItem = createFrameworkTab('Vue', 'fab fa-vuejs', tabIds.vue, text, 'vue');
417
208
  const frameworkTabItems = [javascriptTabItem, cssTabItem, angularTabItem, reactTabItem, vueTabItem];
209
+ // Depois de os ids estarem definidos: o nome do slot depende do id da aba.
210
+ setTabIcon(codeTabItem, 'fab fa-html5');
211
+ setTabIcon(eventsTabItem, 'fas fa-terminal');
212
+ setTabIcon(controlsTabItem, 'fas fa-sliders-h');
213
+ frameworkTabItems.forEach((tab) => {
214
+ setTabIcon(tab, tab.dataset.icon);
215
+ });
418
216
  const frameworkEditors = new Map();
419
217
  const refreshFrameworkEditors = () => {
420
218
  requestAnimationFrame(() => {
@@ -424,6 +222,7 @@ function createExampleElement(path, file, text, isExpanded = false, onOpen) {
424
222
  });
425
223
  };
426
224
  const getFrameworkEditorLanguage = (framework) => {
225
+ if (framework === 'javascript') return 'javascript';
427
226
  if (framework === 'css') return 'css';
428
227
  if (framework === 'angular') return 'typescript';
429
228
  if (framework === 'react') return 'tsx';
@@ -478,6 +277,7 @@ function createExampleElement(path, file, text, isExpanded = false, onOpen) {
478
277
 
479
278
  const button = document.createElement('br-button');
480
279
  button.setAttribute('slot', 'trigger');
280
+ button.setAttribute('type', 'button');
481
281
  button.setAttribute('shape', 'circle');
482
282
  button.setAttribute('density', 'small');
483
283
  button.setAttribute('emphasis', 'secondary');
@@ -499,164 +299,826 @@ function createExampleElement(path, file, text, isExpanded = false, onOpen) {
499
299
  return { tooltip, button, icon, tooltipContent };
500
300
  };
501
301
 
502
- const editorState = { value: text };
302
+ const localDraft =
303
+ window.SHARED_STATE?.p === path && window.SHARED_STATE?.f === file ? null : readPlaygroundDraft(path, file);
304
+ const presetOptions = presets;
305
+ const draftPreset = presetOptions.find(({ id }) => id === localDraft?.presetId);
306
+ const draftBaseline = typeof localDraft?.baselineHtml === 'string' ? localDraft.baselineHtml : null;
307
+ const currentDraftBaseline = draftPreset ? getPresetSource(draftPreset) : text;
308
+ const activeDraft = draftBaseline === currentDraftBaseline ? localDraft : null;
309
+ const editorState = { value: activeDraft?.html || text };
310
+ const vanillaSources = {
311
+ html: editorState.value,
312
+ css: getFrameworkCode(editorState.value, 'css'),
313
+ javascript: getFrameworkCode(editorState.value, 'javascript'),
314
+ };
315
+ let activeVanillaFile = 'html';
316
+ let isSwitchingVanillaFile = false;
317
+ let comparisonBaseline = text;
318
+ const editorHistory = { entries: [editorState.value], index: 0 };
319
+ const editorHistoryLimit = 50;
320
+ let isApplyingEditorValue = false;
321
+ let controlsApi = null;
322
+ let isUpdatingFromControls = false;
323
+ let undoAction;
324
+ let redoAction;
325
+ let diffAction;
326
+ let overflowUndo;
327
+ let overflowRedo;
328
+ let overflowDiff;
503
329
  let editorApi = null;
504
- const getEditorValue = () => editorApi?.getValue() ?? editorState.value;
330
+ // O editor é compartilhado pelas abas index.html/index.css/index.js; fora da
331
+ // aba HTML, o HTML vigente é o último valor aplicado.
332
+ const getEditorValue = () =>
333
+ activeVanillaFile === 'html' ? (editorApi?.getValue() ?? editorState.value) : editorState.value;
505
334
  const refreshEditor = () => {
506
335
  requestAnimationFrame(() => requestAnimationFrame(() => editorApi?.refresh?.()));
507
336
  };
337
+ const updateHistoryActions = () => {
338
+ if (undoAction) undoAction.button.disabled = editorHistory.index === 0;
339
+ if (redoAction) redoAction.button.disabled = editorHistory.index === editorHistory.entries.length - 1;
340
+ if (overflowUndo) overflowUndo.item.disabled = editorHistory.index === 0;
341
+ if (overflowRedo) overflowRedo.item.disabled = editorHistory.index === editorHistory.entries.length - 1;
342
+ };
343
+ const recordEditorHistory = (source) => {
344
+ if (editorHistory.entries[editorHistory.index] === source) return;
345
+ editorHistory.entries = editorHistory.entries.slice(0, editorHistory.index + 1);
346
+ editorHistory.entries.push(source);
347
+ if (editorHistory.entries.length > editorHistoryLimit) editorHistory.entries.shift();
348
+ editorHistory.index = editorHistory.entries.length - 1;
349
+ };
350
+ const moveEditorHistory = (offset) => {
351
+ const nextIndex = editorHistory.index + offset;
352
+ if (nextIndex < 0 || nextIndex >= editorHistory.entries.length) return;
353
+ editorHistory.index = nextIndex;
354
+ setEditorValue(editorHistory.entries[nextIndex], { recordHistory: false });
355
+ };
356
+ const handleEditorKeydown = (event) => {
357
+ if (!(event.ctrlKey || event.metaKey) || event.altKey) return;
358
+ const key = event.key.toLowerCase();
359
+ if (key === 'z') {
360
+ event.preventDefault();
361
+ event.stopPropagation();
362
+ moveEditorHistory(event.shiftKey ? 1 : -1);
363
+ } else if (key === 'y') {
364
+ event.preventDefault();
365
+ event.stopPropagation();
366
+ moveEditorHistory(1);
367
+ }
368
+ };
369
+
370
+ undoAction = createActionButton('fas fa-undo', 'Desfazer alteração', 'Desfazer alteração', () =>
371
+ moveEditorHistory(-1),
372
+ );
373
+ redoAction = createActionButton('fas fa-redo', 'Refazer alteração', 'Refazer alteração', () => moveEditorHistory(1));
374
+ diffAction = createActionButton('fas fa-columns', 'Comparar alterações', 'Comparar alterações', () => {
375
+ diffPanel.hidden = !diffPanel.hidden;
376
+ });
377
+ undoAction.button.setAttribute('aria-keyshortcuts', 'Control+Z Meta+Z');
378
+ redoAction.button.setAttribute('aria-keyshortcuts', 'Control+Y Meta+Y Control+Shift+Z Meta+Shift+Z');
379
+ updateHistoryActions();
380
+ diffAction.button.disabled = true;
381
+
382
+ const presetSelect = document.createElement('br-select');
383
+ presetSelect.className = 'wbc-example-preset';
384
+ presetSelect.id = `${controlsScope}-preset`;
385
+ presetSelect.setAttribute('density', 'small');
386
+ presetSelect.setAttribute('inline', '');
387
+ presetSelect.setAttribute('label', 'Preset');
388
+ const initialPreset =
389
+ presets.find(({ id, source }) => id === activeDraft?.presetId && Boolean(source)) ??
390
+ presets.find(({ id, source }) => id === defaultPreset && Boolean(source)) ??
391
+ presets.find(({ source }) => Boolean(source));
392
+ const initialPresetId = initialPreset?.id || '';
393
+ const getPresetCss = (preset) => preset?.css || getFrameworkCode(editorState.value, 'css');
394
+ const getPresetJavascript = (preset) => preset?.javascript || '';
395
+ // Link compartilhado > rascunho local > arquivos do preset. O estado da URL não é confiável.
396
+ const sharedState = getSharedExampleState(path, file);
397
+ const pickSource = (...values) => values.find((value) => typeof value === 'string');
398
+ vanillaSources.css = pickSource(sharedState?.c, activeDraft?.css, getPresetCss(initialPreset));
399
+ vanillaSources.javascript = pickSource(sharedState?.j, activeDraft?.javascript, getPresetJavascript(initialPreset));
400
+ presetOptions.forEach(({ id, label, source }) => {
401
+ const option = document.createElement('br-select-option');
402
+ option.value = id;
403
+ option.setAttribute('label', label);
404
+ option.textContent = label;
405
+ if (id === initialPresetId) option.setAttribute('selected', '');
406
+ if (id && !source) option.setAttribute('disabled', '');
407
+ presetSelect.appendChild(option);
408
+ });
409
+ presetSelect.value = initialPresetId;
410
+
411
+ // Descrição do preset: linha de largura total entre o cabeçalho e o preview e, se houver,
412
+ // a explicação detalhada em <details>, recolhida a cada troca de preset. O parágrafo é uma
413
+ // região viva, então a troca é anunciada.
414
+ const presetDescription = document.createElement('div');
415
+ presetDescription.className = 'wbc-example-preset-description';
416
+ presetDescription.hidden = true;
417
+ const presetDescriptionText = document.createElement('p');
418
+ presetDescriptionText.className = 'wbc-example-preset-description__text';
419
+ presetDescriptionText.setAttribute('aria-live', 'polite');
420
+ const presetDetails = document.createElement('details');
421
+ presetDetails.className = 'wbc-example-preset-description__details';
422
+ const presetDetailsSummary = document.createElement('summary');
423
+ presetDetailsSummary.textContent = 'Explicação detalhada';
424
+ const presetDetailsBody = document.createElement('div');
425
+ presetDetailsBody.className = 'wbc-example-preset-description__body';
426
+ presetDetails.append(presetDetailsSummary, presetDetailsBody);
427
+ presetDescription.append(presetDescriptionText, presetDetails);
428
+ const updatePresetDescription = (preset) => {
429
+ presetDescription.hidden = !preset?.description;
430
+ presetDescriptionText.textContent = preset?.description ?? '';
431
+ presetDetails.open = false;
432
+ presetDetails.hidden = !preset?.details;
433
+ presetDetailsBody.textContent = preset?.details ?? '';
434
+ };
435
+ updatePresetDescription(initialPreset);
436
+
437
+ let isApplyingPresetFromUrl = false;
438
+ let title;
439
+ const updateExampleLabel = (presetId = presetSelect.value) => {
440
+ const selectedPreset = presetId ? presetOptions.find(({ id }) => id === presetId) : null;
441
+ if (title) title.textContent = selectedPreset?.label || exampleLabel || file;
442
+ };
443
+ if (initialPreset?.source) comparisonBaseline = initialPreset.source;
444
+ presetSelect.addEventListener('change', () => {
445
+ const selectedPreset = presetOptions.find(({ id }) => id === presetSelect.value);
446
+ updateExampleLabel(selectedPreset?.id);
447
+ updatePresetDescription(selectedPreset);
448
+ if (selectedPreset?.source) {
449
+ controlsCssSource = '';
450
+ controlsApi?.reset?.();
451
+ if (!isApplyingPresetFromUrl) updatePresetUrl(file, selectedPreset.id);
452
+ comparisonBaseline = selectedPreset.source;
453
+ vanillaSources.css = getPresetCss(selectedPreset);
454
+ vanillaSources.javascript = getPresetJavascript(selectedPreset);
455
+ activateVanillaFile('html');
456
+ // Presets com o mesmo HTML ainda podem trocar JS/CSS.
457
+ if (selectedPreset.source === editorState.value) {
458
+ renderCurrentPreview(editorState.value);
459
+ persistDraft();
460
+ } else setEditorValue(selectedPreset.source);
461
+ updateDiff(getEditorValue());
462
+ }
463
+ });
464
+ contentDiv._applyPresetFromUrl = (presetId) => {
465
+ const selectedPreset =
466
+ presetOptions.find(({ id, source }) => id === presetId && source) ||
467
+ presetOptions.find(({ id, source }) => id === contentDiv.dataset.defaultPreset && source) ||
468
+ presetOptions.find(({ source }) => source);
469
+ if (!selectedPreset || presetSelect.value === selectedPreset.id) {
470
+ updateExampleLabel(selectedPreset?.id);
471
+ return;
472
+ }
473
+
474
+ isApplyingPresetFromUrl = true;
475
+ presetSelect.value = selectedPreset.id;
476
+ presetSelect.dispatchEvent(new Event('change'));
477
+ isApplyingPresetFromUrl = false;
478
+ };
479
+ const hasPresets = presets.length > 0;
480
+ presetSelect.hidden = !hasPresets;
508
481
 
509
482
  // 1. Copy Action
510
- const copyAction = createActionButton('fas fa-copy', 'Copiar código', 'Copiar código', async () => {
511
- try {
512
- if (navigator.clipboard?.writeText) {
513
- await navigator.clipboard.writeText(getEditorValue());
514
- } else {
515
- const fallback = document.createElement('textarea');
516
- fallback.value = getEditorValue();
517
- fallback.setAttribute('readonly', '');
518
- fallback.style.position = 'fixed';
519
- fallback.style.opacity = '0';
520
- document.body.appendChild(fallback);
521
- fallback.select();
522
- document.execCommand('copy');
523
- fallback.remove();
483
+ const getCopyText = (target) => {
484
+ const source = getEditorValue();
485
+ if (target === 'vanilla') {
486
+ vanillaSources.html = source;
487
+ return `<!-- index.html -->\n${vanillaSources.html}\n\n/* index.css */\n${vanillaSources.css}\n\n// index.js\n${vanillaSources.javascript}`;
488
+ }
489
+ const files = getFrameworkFiles(source, target);
490
+ if (files?.length) {
491
+ return files
492
+ .map(
493
+ (file) => `${file.language === 'html' ? `<!-- ${file.filename} -->` : `// ${file.filename}`}\n${file.code}`,
494
+ )
495
+ .join('\n\n');
496
+ }
497
+ return getFrameworkCode(source, target);
498
+ };
499
+ const copyText = async (target) => {
500
+ const value = getCopyText(target);
501
+ if (navigator.clipboard?.writeText) {
502
+ await navigator.clipboard.writeText(value);
503
+ } else {
504
+ const fallback = document.createElement('textarea');
505
+ fallback.value = value;
506
+ fallback.setAttribute('readonly', '');
507
+ fallback.className = 'wbc-copy-fallback';
508
+ document.body.appendChild(fallback);
509
+ fallback.select();
510
+ document.execCommand('copy');
511
+ fallback.remove();
512
+ }
513
+ };
514
+ const copyMenu = document.createElement('div');
515
+ copyMenu.className = 'wbc-copy-menu';
516
+ copyMenu.setAttribute('role', 'menu');
517
+ copyMenu.setAttribute('aria-label', 'Formato para copiar');
518
+ copyMenu.hidden = true;
519
+ const copyOptions = [
520
+ ['vanilla', 'HTML/CSS/JS'],
521
+ ['angular', 'Angular'],
522
+ ['react', 'React'],
523
+ ['vue', 'Vue'],
524
+ ];
525
+ let copyAction;
526
+ copyAction = createActionButton('fas fa-copy', 'Escolher formato para copiar', 'Copiar código', () => {
527
+ copyMenu.hidden = !copyMenu.hidden;
528
+ copyAction.button.setAttribute('aria-haspopup', 'menu');
529
+ copyAction.button.setAttribute('aria-expanded', String(!copyMenu.hidden));
530
+ });
531
+ copyAction.button.setAttribute('aria-haspopup', 'menu');
532
+ copyAction.button.setAttribute('aria-expanded', 'false');
533
+ copyOptions.forEach(([target, label]) => {
534
+ const option = document.createElement('button');
535
+ option.type = 'button';
536
+ option.setAttribute('role', 'menuitem');
537
+ option.textContent = label;
538
+ option.addEventListener('click', async () => {
539
+ try {
540
+ await copyText(target);
541
+ copyAction.icon.className = 'fas fa-check text-success';
542
+ copyAction.tooltipContent.textContent = 'Copiado!';
543
+ } catch {
544
+ copyAction.tooltipContent.textContent = 'Erro ao copiar';
524
545
  }
525
- copyAction.icon.className = 'fas fa-check text-success';
526
- copyAction.tooltipContent.textContent = 'Copiado!';
527
- } catch {
528
- copyAction.tooltipContent.textContent = 'Erro ao copiar';
546
+ copyMenu.hidden = true;
547
+ copyAction.button.setAttribute('aria-expanded', 'false');
548
+ setTimeout(() => {
549
+ copyAction.icon.className = 'fas fa-copy';
550
+ copyAction.tooltipContent.textContent = 'Escolher formato para copiar';
551
+ }, 2000);
552
+ });
553
+ copyMenu.appendChild(option);
554
+ });
555
+ const copyMenuContainer = document.createElement('div');
556
+ copyMenuContainer.className = 'wbc-copy-menu-container';
557
+ copyMenuContainer.append(copyAction.tooltip, copyMenu);
558
+ copyMenuContainer.addEventListener('keydown', (event) => {
559
+ if (event.key === 'Escape') {
560
+ copyMenu.hidden = true;
561
+ copyAction.button.setAttribute('aria-expanded', 'false');
529
562
  }
530
- setTimeout(() => {
531
- copyAction.icon.className = 'fas fa-copy';
532
- copyAction.tooltipContent.textContent = 'Copiar código';
533
- }, 2000);
534
563
  });
535
564
 
536
- // 2. Share Action
565
+ const setPreviewReducedMotion = (value) => {
566
+ reducedMotionEnabled = Boolean(value);
567
+ contentDiv.setAttribute('data-wbc-reduced-motion', String(reducedMotionEnabled));
568
+ reducedMotionAction.button.setAttribute('aria-pressed', String(reducedMotionEnabled));
569
+ reducedMotionAction.button.classList.toggle('wbc-reduced-motion-action--active', reducedMotionEnabled);
570
+ reducedMotionAction.tooltipContent.textContent = reducedMotionEnabled
571
+ ? 'Desativar movimento reduzido'
572
+ : 'Ativar movimento reduzido';
573
+ if (previewFrame?.contentWindow) {
574
+ previewFrame.contentWindow.postMessage(
575
+ {
576
+ // biome-ignore lint/style/useNamingConvention: nome reservado do protocolo interno de postMessage.
577
+ __playgroundMode: 'reduced-motion',
578
+ value: reducedMotionEnabled,
579
+ // biome-ignore lint/style/useNamingConvention: nome reservado do protocolo interno de postMessage.
580
+ __playgroundChannelId: previewChannelId,
581
+ },
582
+ '*',
583
+ );
584
+ }
585
+ };
586
+ const reducedMotionAction = createActionButton(
587
+ 'fas fa-running',
588
+ reducedMotionEnabled ? 'Desativar movimento reduzido' : 'Ativar movimento reduzido',
589
+ reducedMotionEnabled ? 'Desativar movimento reduzido' : 'Ativar movimento reduzido',
590
+ () => setPreviewReducedMotion(!reducedMotionEnabled),
591
+ );
592
+ reducedMotionAction.button.classList.add('wbc-reduced-motion-action');
593
+ reducedMotionAction.button.classList.toggle('wbc-reduced-motion-action--active', reducedMotionEnabled);
594
+ reducedMotionAction.button.setAttribute('aria-pressed', String(reducedMotionEnabled));
595
+
596
+ const setPreviewTheme = (dark) => {
597
+ darkThemeEnabled = Boolean(dark);
598
+ preview.style.background = darkThemeEnabled ? '#071d41' : '#fff';
599
+ themeAction.button.setAttribute('aria-pressed', String(darkThemeEnabled));
600
+ themeAction.button.classList.toggle('wbc-theme-action--active', darkThemeEnabled);
601
+ themeAction.tooltipContent.textContent = darkThemeEnabled ? 'Usar fundo claro' : 'Usar fundo escuro';
602
+ previewFrame?.contentWindow?.postMessage(
603
+ {
604
+ // biome-ignore lint/style/useNamingConvention: nome reservado do protocolo interno de postMessage.
605
+ __playgroundMode: 'dark',
606
+ value: darkThemeEnabled,
607
+ // biome-ignore lint/style/useNamingConvention: nome reservado do protocolo interno de postMessage.
608
+ __playgroundChannelId: previewChannelId,
609
+ },
610
+ '*',
611
+ );
612
+ };
613
+ const themeAction = createActionButton('fas fa-adjust', 'Usar fundo escuro', 'Mudar fundo', () =>
614
+ setPreviewTheme(!darkThemeEnabled),
615
+ );
616
+ themeAction.button.classList.add('wbc-theme-action');
617
+ themeAction.button.setAttribute('aria-pressed', 'false');
618
+
619
+ const getPreviewFrameSize = () => {
620
+ const frameRect = previewFrame?.getBoundingClientRect();
621
+ const viewportRect = previewViewport.getBoundingClientRect();
622
+ return {
623
+ width: Math.round(viewportRect.width || frameRect?.width || preview.clientWidth || DEV_PREVIEW_MIN_WIDTH),
624
+ height: Math.round(frameRect?.height || viewportRect.height || preview.clientHeight || DEV_PREVIEW_MIN_HEIGHT),
625
+ };
626
+ };
627
+
628
+ const getMaxPreviewWidth = () =>
629
+ Math.max(DEV_PREVIEW_MIN_WIDTH, Math.round(preview.clientWidth || preview.getBoundingClientRect().width));
630
+
631
+ const getMaxPreviewHeight = () => Math.max(DEV_PREVIEW_MIN_HEIGHT, Math.round(window.innerHeight * 0.75));
632
+
633
+ const updatePreviewResizeA11y = () => {
634
+ const { width, height } = getPreviewFrameSize();
635
+ previewWidthResizeHandle.setAttribute('aria-valuemin', String(DEV_PREVIEW_MIN_WIDTH));
636
+ previewWidthResizeHandle.setAttribute('aria-valuemax', String(Math.max(width, getMaxPreviewWidth())));
637
+ previewWidthResizeHandle.setAttribute('aria-valuenow', String(width));
638
+ previewHeightResizeHandle.setAttribute('aria-valuemin', String(DEV_PREVIEW_MIN_HEIGHT));
639
+ previewHeightResizeHandle.setAttribute('aria-valuemax', String(Math.max(height, getMaxPreviewHeight())));
640
+ previewHeightResizeHandle.setAttribute('aria-valuenow', String(height));
641
+ };
642
+
643
+ const updatePreviewWidth = (width, maximumWidth = getMaxPreviewWidth()) => {
644
+ if (!previewFrame) return;
645
+ const currentWidth = getPreviewFrameSize().width;
646
+ const maxWidth = Math.max(currentWidth, maximumWidth);
647
+ const nextWidth = Math.min(Math.max(Math.round(width), DEV_PREVIEW_MIN_WIDTH), maxWidth);
648
+ previewViewport.style.width = `${nextWidth}px`;
649
+ previewViewport.style.maxWidth = 'none';
650
+ updatePreviewResizeA11y();
651
+ };
652
+
653
+ const updatePreviewHeight = (height) => {
654
+ if (!previewFrame) return;
655
+ const currentHeight = getPreviewFrameSize().height;
656
+ const maxHeight = Math.max(currentHeight, getMaxPreviewHeight());
657
+ const nextHeight = Math.min(Math.max(Math.round(height), DEV_PREVIEW_MIN_HEIGHT), maxHeight);
658
+ previewFrame.style.height = `${nextHeight}px`;
659
+ previewFrame.style.maxHeight = 'none';
660
+ hasManualPreviewHeight = true;
661
+ updatePreviewResizeA11y();
662
+ };
663
+
664
+ const stopPreviewResize = () => {
665
+ previewResizeState = null;
666
+ preview.classList.remove('is-resizing');
667
+ previewWidthResizeHandle.classList.remove('is-active');
668
+ previewHeightResizeHandle.classList.remove('is-active');
669
+ window.removeEventListener('mousemove', handlePreviewResizeMove);
670
+ window.removeEventListener('mouseup', stopPreviewResize);
671
+ };
672
+
673
+ const handlePreviewResizeMove = (event) => {
674
+ if (previewResizeState?.axis === 'vertical') {
675
+ updatePreviewWidth(
676
+ previewResizeState.width + event.clientX - previewResizeState.clientX,
677
+ previewResizeState.maximumWidth,
678
+ );
679
+ } else if (previewResizeState?.axis === 'horizontal') {
680
+ updatePreviewHeight(previewResizeState.height + event.clientY - previewResizeState.clientY);
681
+ }
682
+ };
683
+
684
+ const startPreviewResize = (axis, event) => {
685
+ event.preventDefault();
686
+ event.stopPropagation();
687
+ stopPreviewResize();
688
+ const { width, height } = getPreviewFrameSize();
689
+ const previewRect = preview.getBoundingClientRect();
690
+ const viewportRect = previewViewport.getBoundingClientRect();
691
+ const viewportLeft = Math.max(0, Math.round(viewportRect.left - previewRect.left + preview.scrollLeft));
692
+ const maximumWidth = Math.max(DEV_PREVIEW_MIN_WIDTH, preview.clientWidth - viewportLeft);
693
+ previewResizeState = { axis, clientX: event.clientX, clientY: event.clientY, width, height, maximumWidth };
694
+ if (axis === 'vertical') {
695
+ previewViewport.style.margin = '0';
696
+ previewViewport.style.marginLeft = `${viewportLeft}px`;
697
+ }
698
+ preview.classList.add('is-resizing');
699
+ (axis === 'vertical' ? previewWidthResizeHandle : previewHeightResizeHandle).classList.add('is-active');
700
+ window.addEventListener('mousemove', handlePreviewResizeMove);
701
+ window.addEventListener('mouseup', stopPreviewResize);
702
+ };
703
+
704
+ const handlePreviewResizeKeydown = (axis, event) => {
705
+ const { width, height } = getPreviewFrameSize();
706
+
707
+ if (axis === 'vertical') {
708
+ const delta = getPreviewResizeDelta(event.key, 'ArrowLeft', 'ArrowRight');
709
+ if (!delta) return;
710
+ event.preventDefault();
711
+ updatePreviewWidth(width + delta);
712
+ return;
713
+ }
714
+
715
+ const delta = getPreviewResizeDelta(event.key, 'ArrowUp', 'ArrowDown');
716
+ if (delta) {
717
+ event.preventDefault();
718
+ updatePreviewHeight(height + delta);
719
+ }
720
+ };
721
+
722
+ previewWidthResizeHandle.addEventListener('mousedown', (event) => startPreviewResize('vertical', event));
723
+ previewWidthResizeHandle.addEventListener('keydown', (event) => handlePreviewResizeKeydown('vertical', event));
724
+ previewHeightResizeHandle.addEventListener('mousedown', (event) => startPreviewResize('horizontal', event));
725
+ previewHeightResizeHandle.addEventListener('keydown', (event) => handlePreviewResizeKeydown('horizontal', event));
726
+ window.addEventListener('resize', updatePreviewResizeA11y, { signal: exampleAbortController.signal });
727
+ exampleAbortController.signal.addEventListener('abort', stopPreviewResize, { once: true });
728
+
729
+ const setViewport = (viewport) => {
730
+ activeViewport = viewport;
731
+ hasManualPreviewHeight = false;
732
+ stopPreviewResize();
733
+ const deviceMode = viewport.mode ?? 'web';
734
+ previewViewport.classList.toggle('wbc-example-preview-viewport--device', deviceMode !== 'web');
735
+ previewViewport.classList.toggle('wbc-example-preview-viewport--ios', deviceMode === 'ios');
736
+ previewViewport.classList.toggle('wbc-example-preview-viewport--android', deviceMode === 'android');
737
+ if (!previewFrame) return;
738
+
739
+ if (!viewport.width) {
740
+ preview.classList.remove('wbc-example-preview--viewport');
741
+ preview.style.removeProperty('max-height');
742
+ preview.style.removeProperty('overflow');
743
+ previewFrame.style.removeProperty('width');
744
+ previewFrame.style.removeProperty('height');
745
+ previewFrame.style.removeProperty('max-height');
746
+ previewFrame.style.removeProperty('max-width');
747
+ previewFrame.style.removeProperty('margin');
748
+ previewViewport.style.removeProperty('width');
749
+ previewViewport.style.removeProperty('max-width');
750
+ previewViewport.style.removeProperty('margin');
751
+ previewViewport.style.removeProperty('margin-left');
752
+ updatePreviewResizeA11y();
753
+ return;
754
+ }
755
+
756
+ preview.classList.add('wbc-example-preview--viewport');
757
+ preview.style.maxHeight = '75vh';
758
+ preview.style.overflow = 'auto';
759
+ previewViewport.style.width = `${viewport.width}px`;
760
+ previewViewport.style.maxWidth = 'none';
761
+ previewViewport.style.removeProperty('margin-left');
762
+ previewViewport.style.margin = '0 auto';
763
+ previewFrame.style.width = '100%';
764
+ previewFrame.style.height = `${viewport.height}px`;
765
+ previewFrame.style.maxWidth = 'none';
766
+ previewFrame.style.maxHeight = 'none';
767
+ previewFrame.style.removeProperty('margin');
768
+ updatePreviewResizeA11y();
769
+ };
770
+ const viewportActions = DEV_VIEWPORTS.map((viewport) => {
771
+ const action = createActionButton(viewport.icon, viewport.label, viewport.label, () => {
772
+ setViewport(viewport);
773
+ viewportActions.forEach(({ viewport: item, action: itemAction }) => {
774
+ itemAction.button.classList.toggle('wbc-viewport-action--active', item.id === viewport.id);
775
+ });
776
+ });
777
+ action.viewport = viewport;
778
+ action.button.classList.add('wbc-viewport-action');
779
+ action.button.classList.toggle('wbc-viewport-action--active', viewport.id === activeViewport.id);
780
+ return { viewport, action };
781
+ });
782
+
783
+ let overflowShare;
784
+ const handleShare = async () => {
785
+ try {
786
+ await loadLzString();
787
+ } catch {
788
+ alert('Biblioteca de compartilhamento não carregada.');
789
+ return;
790
+ }
791
+ const state = {
792
+ p: path,
793
+ f: file,
794
+ h: getEditorValue(),
795
+ j: vanillaSources.javascript,
796
+ c: vanillaSources.css,
797
+ // Mantém a associação do código compartilhado ao preset para links legados e edição posterior.
798
+ presetId: presetSelect.value || undefined,
799
+ };
800
+ try {
801
+ const json = JSON.stringify(state);
802
+ const encoded = window.LZString.compressToEncodedURIComponent(json);
803
+ const url = new URL(window.location.href);
804
+ url.searchParams.set('pg_state', encoded);
805
+ url.hash = getExampleHash(file, presetSelect.value || undefined);
806
+
807
+ await navigator.clipboard.writeText(url.toString());
808
+
809
+ shareAction.icon.className = 'fas fa-check text-success';
810
+ shareAction.tooltipContent.textContent = 'Link copiado!';
811
+ if (overflowShare) {
812
+ overflowShare.iconEl.className = 'fas fa-check text-success';
813
+ overflowShare.textEl.textContent = 'Link copiado!';
814
+ }
815
+ setTimeout(() => {
816
+ shareAction.icon.className = 'fas fa-share-alt';
817
+ shareAction.tooltipContent.textContent = 'Compartilhar exemplo';
818
+ if (overflowShare) {
819
+ overflowShare.iconEl.className = 'fas fa-share-alt';
820
+ overflowShare.textEl.textContent = 'Compartilhar exemplo';
821
+ }
822
+ }, 2000);
823
+ } catch (err) {
824
+ console.error(err);
825
+ shareAction.tooltipContent.textContent = 'Erro ao compartilhar';
826
+ if (overflowShare) overflowShare.textEl.textContent = 'Erro ao compartilhar';
827
+ setTimeout(() => {
828
+ shareAction.icon.className = 'fas fa-share-alt';
829
+ shareAction.tooltipContent.textContent = 'Compartilhar exemplo';
830
+ if (overflowShare) {
831
+ overflowShare.iconEl.className = 'fas fa-share-alt';
832
+ overflowShare.textEl.textContent = 'Compartilhar exemplo';
833
+ }
834
+ }, 2000);
835
+ }
836
+ };
837
+
537
838
  const shareAction = createActionButton(
538
839
  'fas fa-share-alt',
539
840
  'Compartilhar exemplo',
540
841
  'Compartilhar exemplo',
541
- async () => {
542
- try {
543
- await loadLzString();
544
- } catch {
545
- alert('Biblioteca de compartilhamento não carregada.');
546
- return;
547
- }
548
- const state = {
549
- p: path,
550
- f: file,
551
- h: getEditorValue(),
552
- };
553
- try {
554
- const json = JSON.stringify(state);
555
- const encoded = window.LZString.compressToEncodedURIComponent(json);
556
- const url = new URL(window.location.href);
557
- url.searchParams.set('pg_state', encoded);
558
- url.hash = getExampleHash(file);
559
-
560
- await navigator.clipboard.writeText(url.toString());
561
-
562
- shareAction.icon.className = 'fas fa-check text-success';
563
- shareAction.tooltipContent.textContent = 'Link copiado!';
564
- setTimeout(() => {
565
- shareAction.icon.className = 'fas fa-share-alt';
566
- shareAction.tooltipContent.textContent = 'Compartilhar exemplo';
567
- }, 2000);
568
- } catch (err) {
569
- console.error(err);
570
- shareAction.tooltipContent.textContent = 'Erro ao compartilhar';
571
- setTimeout(() => {
572
- shareAction.icon.className = 'fas fa-share-alt';
573
- shareAction.tooltipContent.textContent = 'Compartilhar exemplo';
574
- }, 2000);
575
- }
576
- },
842
+ handleShare,
577
843
  );
578
844
 
579
845
  // 3. Fullscreen Action
846
+ let isClosingFullscreen = false;
847
+ const closeFullscreen = () => {
848
+ if (!contentDiv.classList.contains('is-fullscreen') || isClosingFullscreen) return;
849
+ isClosingFullscreen = true;
850
+ contentDiv.classList.add('is-fullscreen-exiting');
851
+ setTimeout(() => {
852
+ contentDiv.classList.remove('is-fullscreen');
853
+ contentDiv.classList.remove('is-fullscreen-exiting');
854
+ isClosingFullscreen = false;
855
+ fsAction.icon.className = 'fas fa-expand-arrows-alt';
856
+ fsAction.tooltipContent.textContent = 'Tela cheia';
857
+ fsAction.button.focus();
858
+ }, 200);
859
+ };
860
+
580
861
  const fsAction = createActionButton('fas fa-expand-arrows-alt', 'Tela cheia', 'Tela cheia', () => {
581
- const isFullscreen = contentDiv.classList.toggle('is-fullscreen');
582
- if (isFullscreen) {
862
+ if (contentDiv.classList.contains('is-fullscreen')) {
863
+ closeFullscreen();
864
+ } else {
865
+ contentDiv.classList.add('is-fullscreen');
583
866
  fsAction.icon.className = 'fas fa-compress-arrows-alt';
584
867
  fsAction.tooltipContent.textContent = 'Fechar tela cheia';
585
868
  requestAnimationFrame(() => editorApi?.refresh?.());
586
- } else {
587
- fsAction.icon.className = 'fas fa-expand-arrows-alt';
588
- fsAction.tooltipContent.textContent = 'Tela cheia';
589
869
  }
590
870
  });
871
+ document.addEventListener(
872
+ 'keydown',
873
+ (event) => {
874
+ if (event.key !== 'Escape' || !contentDiv.classList.contains('is-fullscreen')) return;
875
+ event.preventDefault();
876
+ closeFullscreen();
877
+ },
878
+ { signal: exampleAbortController.signal },
879
+ );
591
880
 
592
881
  // --- EXAMPLE CARD HEADER ---
593
882
  const header = document.createElement('div');
594
883
  header.className = 'wbc-example-header';
595
884
 
596
- const title = document.createElement('h3');
597
- title.textContent = file;
885
+ title = document.createElement('h3');
886
+ updateExampleLabel();
598
887
  header.appendChild(title);
599
888
 
600
- // Group all actions and toggle on the right
889
+ // Group actions: expanded toolbar vs compact dropdown
601
890
  const headerActions = document.createElement('div');
602
891
  headerActions.className = 'wbc-example-header-actions';
603
892
 
604
- const exampleToggleTooltip = document.createElement('br-tooltip');
605
- exampleToggleTooltip.setAttribute('position', 'bottom');
893
+ const expandedActions = document.createElement('div');
894
+ expandedActions.className = 'wbc-example-header-actions-expanded';
895
+ expandedActions.append(
896
+ undoAction.tooltip,
897
+ redoAction.tooltip,
898
+ diffAction.tooltip,
899
+ ...viewportActions.map(({ action }) => action.tooltip),
900
+ copyMenuContainer,
901
+ reducedMotionAction.tooltip,
902
+ shareAction.tooltip,
903
+ themeAction.tooltip,
904
+ );
905
+
906
+ // Overflow container for compact toolbar
907
+ const overflowContainer = document.createElement('div');
908
+ overflowContainer.className = 'wbc-toolbar-overflow-container';
606
909
 
607
- const exampleToggle = document.createElement('br-button');
608
- exampleToggle.className = 'wbc-example-toggle';
609
- exampleToggle.setAttribute('density', 'small');
610
- exampleToggle.setAttribute('emphasis', 'secondary');
611
- exampleToggle.setAttribute('shape', 'circle');
612
- exampleToggle.setAttribute('aria-label', isExpanded ? 'Recolher exemplo' : 'Expandir exemplo');
613
- exampleToggle.setAttribute('slot', 'trigger');
910
+ const overflowMenu = document.createElement('div');
911
+ overflowMenu.className = 'wbc-toolbar-overflow-menu';
912
+ overflowMenu.setAttribute('role', 'menu');
913
+ overflowMenu.setAttribute('aria-label', 'Mais opções');
914
+ overflowMenu.hidden = true;
614
915
 
615
- const exampleIcon = document.createElement('i');
616
- exampleIcon.className = `fas fa-chevron-${isExpanded ? 'up' : 'down'}`;
617
- exampleToggle.appendChild(exampleIcon);
916
+ const closeOverflow = () => {
917
+ overflowMenu.hidden = true;
918
+ overflowAction.button.setAttribute('aria-expanded', 'false');
919
+ overflowAction.button.classList.remove('wbc-toolbar-overflow-action--active');
920
+ };
618
921
 
619
- const exampleToggleTooltipContent = document.createElement('div');
620
- exampleToggleTooltipContent.setAttribute('slot', 'content');
621
- exampleToggleTooltipContent.setAttribute('position', 'bottom');
622
- exampleToggleTooltipContent.textContent = isExpanded ? 'Recolher exemplo' : 'Expandir exemplo';
922
+ const createOverflowItem = ({ icon, label, onClick, isCheckbox = false }) => {
923
+ const item = document.createElement('button');
924
+ item.type = 'button';
925
+ item.className = 'wbc-toolbar-overflow-menu-item';
926
+ item.setAttribute('role', isCheckbox ? 'menuitemcheckbox' : 'menuitem');
623
927
 
624
- exampleToggleTooltip.append(exampleToggle, exampleToggleTooltipContent);
928
+ const iconEl = document.createElement('i');
929
+ iconEl.className = icon;
930
+ iconEl.setAttribute('aria-hidden', 'true');
625
931
 
626
- header.setAttribute('slot', 'trigger');
627
- header.addEventListener('click', (event) => {
628
- if (event.target.closest('.wbc-example-header-actions') && !event.target.closest('.wbc-example-toggle')) {
629
- event.stopPropagation();
932
+ const textEl = document.createElement('span');
933
+ textEl.textContent = label;
934
+
935
+ item.append(iconEl, textEl);
936
+ item.addEventListener('click', (event) => {
937
+ onClick(event);
938
+ closeOverflow();
939
+ });
940
+ return { item, iconEl, textEl };
941
+ };
942
+
943
+ overflowUndo = createOverflowItem({
944
+ icon: 'fas fa-undo',
945
+ label: 'Desfazer alteração',
946
+ onClick: () => moveEditorHistory(-1),
947
+ });
948
+
949
+ overflowRedo = createOverflowItem({
950
+ icon: 'fas fa-redo',
951
+ label: 'Refazer alteração',
952
+ onClick: () => moveEditorHistory(1),
953
+ });
954
+
955
+ overflowDiff = createOverflowItem({
956
+ icon: 'fas fa-columns',
957
+ label: 'Comparar alterações',
958
+ onClick: () => {
959
+ diffPanel.hidden = !diffPanel.hidden;
960
+ },
961
+ });
962
+
963
+ const overflowCopy = createOverflowItem({
964
+ icon: 'fas fa-copy',
965
+ label: 'Copiar código',
966
+ onClick: async () => {
967
+ await copyText('vanilla');
968
+ },
969
+ });
970
+
971
+ const overflowViewports = DEV_VIEWPORTS.map((viewport) =>
972
+ createOverflowItem({
973
+ icon: viewport.icon,
974
+ label: viewport.label,
975
+ onClick: () => {
976
+ setViewport(viewport);
977
+ viewportActions.forEach(({ viewport: item, action: itemAction }) => {
978
+ itemAction.button.classList.toggle('wbc-viewport-action--active', item.id === viewport.id);
979
+ });
980
+ },
981
+ }),
982
+ );
983
+
984
+ const overflowReducedMotion = createOverflowItem({
985
+ icon: 'fas fa-running',
986
+ label: `Movimento reduzido (${reducedMotionEnabled ? 'Ativo' : 'Inativo'})`,
987
+ isCheckbox: true,
988
+ onClick: () => setPreviewReducedMotion(!reducedMotionEnabled),
989
+ });
990
+
991
+ overflowShare = createOverflowItem({
992
+ icon: 'fas fa-share-alt',
993
+ label: 'Compartilhar exemplo',
994
+ onClick: () => handleShare(),
995
+ });
996
+
997
+ const overflowTheme = createOverflowItem({
998
+ icon: 'fas fa-adjust',
999
+ label: `Alternar fundo (${darkThemeEnabled ? 'Escuro' : 'Claro'})`,
1000
+ onClick: () => setPreviewTheme(!darkThemeEnabled),
1001
+ });
1002
+
1003
+ const updateOverflowMenu = () => {
1004
+ overflowUndo.item.disabled = undoAction.button.disabled;
1005
+ overflowRedo.item.disabled = redoAction.button.disabled;
1006
+ overflowDiff.item.disabled = diffAction.button.disabled;
1007
+ DEV_VIEWPORTS.forEach((viewport, index) => {
1008
+ overflowViewports[index].item.classList.toggle('is-active', viewport.id === activeViewport.id);
1009
+ });
1010
+ overflowReducedMotion.item.classList.toggle('is-active', reducedMotionEnabled);
1011
+ overflowReducedMotion.item.setAttribute('aria-checked', String(reducedMotionEnabled));
1012
+ overflowReducedMotion.textEl.textContent = `Movimento reduzido (${reducedMotionEnabled ? 'Ativo' : 'Inativo'})`;
1013
+ overflowTheme.item.classList.toggle('is-active', darkThemeEnabled);
1014
+ overflowTheme.textEl.textContent = `Alternar fundo (${darkThemeEnabled ? 'Escuro' : 'Claro'})`;
1015
+ };
1016
+
1017
+ overflowMenu.append(
1018
+ overflowUndo.item,
1019
+ overflowRedo.item,
1020
+ overflowDiff.item,
1021
+ overflowCopy.item,
1022
+ ...overflowViewports.map(({ item }) => item),
1023
+ overflowReducedMotion.item,
1024
+ overflowShare.item,
1025
+ overflowTheme.item,
1026
+ );
1027
+
1028
+ const overflowAction = createActionButton('fas fa-ellipsis-v', 'Mais opções', 'Mais opções', () => {
1029
+ const isHidden = !overflowMenu.hidden;
1030
+ if (isHidden) {
1031
+ closeOverflow();
1032
+ } else {
1033
+ updateOverflowMenu();
1034
+ overflowMenu.hidden = false;
1035
+ overflowAction.button.setAttribute('aria-expanded', 'true');
1036
+ overflowAction.button.classList.add('wbc-toolbar-overflow-action--active');
630
1037
  }
631
1038
  });
1039
+ overflowAction.button.classList.add('wbc-toolbar-overflow-action');
1040
+ overflowAction.button.setAttribute('aria-haspopup', 'menu');
1041
+ overflowAction.button.setAttribute('aria-expanded', 'false');
632
1042
 
633
- const updateExampleToggle = (open) => {
634
- exampleIcon.className = `fas fa-chevron-${open ? 'up' : 'down'}`;
635
- exampleToggle.setAttribute('aria-label', open ? 'Recolher exemplo' : 'Expandir exemplo');
636
- exampleToggleTooltipContent.textContent = open ? 'Recolher exemplo' : 'Expandir exemplo';
637
- if (open) requestAnimationFrame(() => editorApi?.refresh?.());
638
- };
639
-
640
- dropdown.addEventListener('brDropdownOpenChange', (event) => {
641
- const open = event.detail.open;
642
- updateExampleToggle(open);
643
- if (open) {
644
- if (!isInitialized) {
645
- dropdown.append(preview, fullscreenBottomPanel);
646
- initializeExample?.();
647
- isInitialized = true;
648
- }
649
- onOpen?.(file, contentDiv);
650
- } else if (window.location.hash === getExampleHash(file)) {
651
- window.history.replaceState({}, '', `${window.location.pathname}${window.location.search}`);
1043
+ overflowContainer.append(overflowAction.tooltip, overflowMenu);
1044
+
1045
+ const handleOverflowOutsideClick = (event) => {
1046
+ if (!overflowContainer.contains(event.target)) {
1047
+ closeOverflow();
1048
+ }
1049
+ };
1050
+ document.addEventListener('click', handleOverflowOutsideClick);
1051
+ exampleAbortController.signal.addEventListener(
1052
+ 'abort',
1053
+ () => {
1054
+ document.removeEventListener('click', handleOverflowOutsideClick);
1055
+ },
1056
+ { once: true },
1057
+ );
1058
+
1059
+ overflowContainer.addEventListener('keydown', (event) => {
1060
+ if (event.key === 'Escape') {
1061
+ closeOverflow();
1062
+ overflowAction.button.focus();
652
1063
  }
653
1064
  });
654
1065
 
655
- headerActions.append(copyAction.tooltip, shareAction.tooltip, fsAction.tooltip, exampleToggleTooltip);
1066
+ const collapsedActions = document.createElement('div');
1067
+ collapsedActions.className = 'wbc-example-header-actions-collapsed';
1068
+ collapsedActions.append(overflowContainer);
1069
+
1070
+ headerActions.append(presetSelect, expandedActions, collapsedActions, fsAction.tooltip);
656
1071
  header.appendChild(headerActions);
657
1072
 
1073
+ const updateToolbarLayout = () => {
1074
+ const isCompact = header.clientWidth > 0 && header.clientWidth < 840;
1075
+ header.classList.toggle('is-compact-toolbar', isCompact);
1076
+ header.classList.toggle('is-stacked-toolbar', header.clientWidth > 0 && header.clientWidth < 576);
1077
+ };
1078
+ const headerResizeObserver = new ResizeObserver(updateToolbarLayout);
1079
+ headerResizeObserver.observe(header);
1080
+ exampleAbortController.signal.addEventListener('abort', () => headerResizeObserver.disconnect(), { once: true });
1081
+
658
1082
  const editorWrapper = document.createElement('div');
659
1083
  editorWrapper.className = 'wbc-example-editor-wrapper';
1084
+ editorWrapper.addEventListener('keydown', handleEditorKeydown, true);
1085
+
1086
+ const diffPanel = document.createElement('section');
1087
+ diffPanel.className = 'wbc-example-diff';
1088
+ diffPanel.hidden = true;
1089
+ diffPanel.setAttribute('aria-label', 'Diff das alterações do exemplo');
1090
+ const diffTitle = document.createElement('h4');
1091
+ diffTitle.className = 'wbc-example-diff__title';
1092
+ diffTitle.textContent = 'Alterações (formatação ignorada)';
1093
+ const diffCode = document.createElement('pre');
1094
+ diffCode.className = 'wbc-example-diff__code';
1095
+ diffPanel.append(diffTitle, diffCode);
1096
+
1097
+ const renderDiff = (diff) => {
1098
+ const fragment = document.createDocumentFragment();
1099
+ diff.lines.forEach((line) => {
1100
+ const lineElement = document.createElement('span');
1101
+ lineElement.className = 'wbc-example-diff__line';
1102
+ if (line.startsWith('---') || line.startsWith('+++')) lineElement.classList.add('is-header');
1103
+ else if (line.startsWith('+')) lineElement.classList.add('is-added');
1104
+ else if (line.startsWith('-')) lineElement.classList.add('is-removed');
1105
+ else if (line.startsWith('@')) lineElement.classList.add('is-hunk');
1106
+ lineElement.textContent = line || ' ';
1107
+ fragment.appendChild(lineElement);
1108
+ });
1109
+ diffCode.replaceChildren(fragment);
1110
+ };
1111
+ const updateDiff = (source) => {
1112
+ const diff = window.WBCPlaygroundCore?.createUnifiedDiff(comparisonBaseline, source) || {
1113
+ changed: source !== comparisonBaseline,
1114
+ lines: source === comparisonBaseline ? [] : [`- ${comparisonBaseline}`, `+ ${source}`],
1115
+ };
1116
+ const hasChanges = diff.changed;
1117
+ diffAction.button.disabled = !hasChanges;
1118
+ if (overflowDiff) overflowDiff.item.disabled = !hasChanges;
1119
+ if (!hasChanges) diffPanel.hidden = true;
1120
+ renderDiff(diff);
1121
+ };
660
1122
 
661
1123
  const eventsWrapper = document.createElement('div');
662
1124
  eventsWrapper.className = 'wbc-example-events-wrapper';
@@ -666,34 +1128,57 @@ function createExampleElement(path, file, text, isExpanded = false, onOpen) {
666
1128
 
667
1129
  const filterContainer = document.createElement('div');
668
1130
  filterContainer.className = 'wbc-events-filter-container';
669
- filterContainer.style.display = 'flex';
670
- filterContainer.style.gap = '8px';
671
- filterContainer.style.alignItems = 'flex-end';
672
- filterContainer.style.marginBottom = '8px';
673
1131
 
674
1132
  const eventFilterInput = document.createElement('br-input');
1133
+ eventFilterInput.className = 'wbc-events-filter-input';
675
1134
  eventFilterInput.setAttribute('placeholder', 'Filtrar eventos...');
676
1135
  eventFilterInput.setAttribute('density', 'small');
677
- eventFilterInput.style.flex = '1';
1136
+ const eventKindFilter = document.createElement('select');
1137
+ eventKindFilter.className = 'wbc-event-kind-filter';
1138
+ eventKindFilter.setAttribute('aria-label', 'Tipo de evento');
1139
+ [
1140
+ ['all', 'Todos'],
1141
+ ['native', 'Nativos'],
1142
+ ['custom', 'Customizados'],
1143
+ ['component', 'Por componente'],
1144
+ ].forEach(([value, label]) => {
1145
+ eventKindFilter.add(new Option(label, value));
1146
+ });
678
1147
 
679
1148
  const copyEventsAction = createActionButton(
680
1149
  'fas fa-copy',
681
- 'Copiar lista de eventos',
682
- 'Copiar lista de eventos',
1150
+ 'Exportar eventos capturados',
1151
+ 'Exportar eventos capturados',
683
1152
  async () => {
684
- const visibleItems = Array.from(eventsList.querySelectorAll('li')).filter((li) => li.style.display !== 'none');
685
- const textToCopy = visibleItems
686
- .map((li) => {
687
- const name = li.querySelector('.wbc-event-console-event-name').textContent;
688
- const target = li.querySelector('.wbc-event-console-target').textContent;
689
- const payload = li.querySelector('.wbc-event-console-detail')?.textContent || '';
690
- return `${name}${target}${payload ? `\nPayload: ${payload}` : ''}`;
1153
+ const filter = String(eventFilterInput.value ?? '').toLowerCase();
1154
+ const kind = eventKindFilter.value;
1155
+ const textToCopy = eventEntries
1156
+ .filter((entry) => {
1157
+ const kindMatches =
1158
+ kind === 'all' ||
1159
+ (kind === 'native' && !entry.custom) ||
1160
+ (kind === 'custom' && entry.custom) ||
1161
+ (kind === 'component' && /br-[a-z0-9-]+/i.test(`${entry.target} ${entry.currentTarget || ''}`));
1162
+ return (
1163
+ kindMatches &&
1164
+ `${entry.eventType} ${entry.target} ${entry.currentTarget || ''}`.toLowerCase().includes(filter)
1165
+ );
691
1166
  })
1167
+ .map((entry) => serialize(entry))
692
1168
  .join('\n---\n');
693
1169
 
694
1170
  try {
695
1171
  if (navigator.clipboard?.writeText) {
696
1172
  await navigator.clipboard.writeText(textToCopy);
1173
+ } else {
1174
+ const fallback = document.createElement('textarea');
1175
+ fallback.value = textToCopy;
1176
+ fallback.setAttribute('readonly', '');
1177
+ fallback.className = 'wbc-copy-fallback';
1178
+ document.body.appendChild(fallback);
1179
+ fallback.select();
1180
+ document.execCommand('copy');
1181
+ fallback.remove();
697
1182
  }
698
1183
  copyEventsAction.icon.className = 'fas fa-check text-success';
699
1184
  copyEventsAction.tooltipContent.textContent = 'Copiado!';
@@ -702,28 +1187,28 @@ function createExampleElement(path, file, text, isExpanded = false, onOpen) {
702
1187
  }
703
1188
  setTimeout(() => {
704
1189
  copyEventsAction.icon.className = 'fas fa-copy';
705
- copyEventsAction.tooltipContent.textContent = 'Copiar lista de eventos';
1190
+ copyEventsAction.tooltipContent.textContent = 'Exportar eventos capturados';
706
1191
  }, 2000);
707
1192
  },
708
1193
  );
709
1194
 
710
- filterContainer.append(eventFilterInput, copyEventsAction.tooltip);
1195
+ filterContainer.append(eventFilterInput, eventKindFilter, copyEventsAction.tooltip);
711
1196
 
712
1197
  const eventsHelp = document.createElement('p');
713
1198
  eventsHelp.className = 'wbc-events-help';
714
- eventsHelp.textContent = 'Eventos emitidos pelo componente aparecem abaixo.';
1199
+ eventsHelp.textContent = 'Eventos e mensagens de runtime do preview aparecem abaixo.';
715
1200
 
716
1201
  const eventsActions = document.createElement('div');
717
1202
  eventsActions.className = 'wbc-events-actions';
718
- eventsActions.style.display = 'flex';
719
- eventsActions.style.gap = '5px';
720
1203
 
721
1204
  const pauseBtn = document.createElement('br-button');
1205
+ pauseBtn.setAttribute('type', 'button');
722
1206
  pauseBtn.setAttribute('density', 'small');
723
1207
  pauseBtn.setAttribute('emphasis', 'secondary');
724
1208
  pauseBtn.textContent = 'Pausar';
725
1209
 
726
1210
  const clearBtn = document.createElement('br-button');
1211
+ clearBtn.setAttribute('type', 'button');
727
1212
  clearBtn.setAttribute('density', 'small');
728
1213
  clearBtn.setAttribute('emphasis', 'secondary');
729
1214
  clearBtn.textContent = 'Limpar';
@@ -736,31 +1221,47 @@ function createExampleElement(path, file, text, isExpanded = false, onOpen) {
736
1221
 
737
1222
  eventsWrapper.append(eventsHeader, eventsList);
738
1223
 
1224
+ const eventEntries = [];
1225
+ let eventCounter = 0;
1226
+
739
1227
  const applyFilter = () => {
740
1228
  const val = String(eventFilterInput.value ?? '').toLowerCase();
1229
+ const kind = eventKindFilter.value;
741
1230
  Array.from(eventsList.children).forEach((li) => {
742
1231
  const text = li.textContent.toLowerCase();
743
- li.style.display = text.includes(val) ? '' : 'none';
1232
+ const kindMatches =
1233
+ kind === 'all' ||
1234
+ li.dataset.eventKind === kind ||
1235
+ (kind === 'component' && /br-[a-z0-9-]+/i.test(li.dataset.eventTarget || ''));
1236
+ li.hidden = !kindMatches || !text.includes(val);
744
1237
  });
745
1238
  };
746
1239
 
747
1240
  eventFilterInput.addEventListener('input', applyFilter);
748
- eventFilterInput.addEventListener('valueChange', applyFilter);
1241
+ eventKindFilter.addEventListener('change', applyFilter);
749
1242
 
750
1243
  let newEventsCount = 0;
751
1244
  let isPaused = false;
1245
+ const updateConsoleCounter = () => {
1246
+ const count = eventEntries.length + runtimeEntries.length;
1247
+ if (count > 0) eventsTabItem.setAttribute('counter', count > 99 ? '99+' : String(count));
1248
+ else eventsTabItem.removeAttribute('counter');
1249
+ };
1250
+
1251
+ const markConsoleEntry = () => {
1252
+ const isActive = tabComponent.activeTabId === tabIds.events;
1253
+ if (!isActive) {
1254
+ newEventsCount++;
1255
+ eventsTabItem.setAttribute('label', `Console (${newEventsCount})`);
1256
+ }
1257
+ updateConsoleCounter();
1258
+ };
752
1259
 
753
1260
  pauseBtn.addEventListener('click', () => {
754
1261
  isPaused = !isPaused;
755
1262
  pauseBtn.textContent = isPaused ? 'Continuar' : 'Pausar';
756
1263
  });
757
1264
 
758
- clearBtn.addEventListener('click', () => {
759
- eventsList.replaceChildren();
760
- eventsTabItem.setAttribute('label', 'Console');
761
- newEventsCount = 0;
762
- });
763
-
764
1265
  const serialize = (value) => {
765
1266
  if (value === undefined) return '';
766
1267
  try {
@@ -789,97 +1290,306 @@ function createExampleElement(path, file, text, isExpanded = false, onOpen) {
789
1290
  return `${target.localName}${id}${classes}`;
790
1291
  };
791
1292
 
792
- const addEventEntry = (event, dispatchedBy, targetDescription) => {
793
- if (isPaused) return;
1293
+ const createEventEntry = (event, dispatchedBy, targetDescription, metadata = {}) => {
1294
+ eventCounter += 1;
1295
+ return {
1296
+ id: metadata.eventId || `event-${eventCounter}`,
1297
+ eventType: metadata.eventType || event.type,
1298
+ custom: Boolean(metadata.custom || event instanceof CustomEvent),
1299
+ detail: metadata.detail ?? (event instanceof CustomEvent ? event.detail : undefined),
1300
+ target: metadata.target || targetDescription || describeTarget(event.target || dispatchedBy),
1301
+ currentTarget: metadata.currentTarget,
1302
+ composedPath: metadata.composedPath || [],
1303
+ bubbles: metadata.bubbles ?? Boolean(event.bubbles),
1304
+ composed: metadata.composed ?? Boolean(event.composed),
1305
+ cancelable: metadata.cancelable ?? Boolean(event.cancelable),
1306
+ timeStamp: metadata.timeStamp ?? event.timeStamp,
1307
+ };
1308
+ };
1309
+
1310
+ const createEventDetails = (detail) => {
1311
+ const detailsEl = document.createElement('details');
1312
+ detailsEl.className = 'wbc-event-console-details-container';
1313
+ detailsEl.open = true;
1314
+
1315
+ const summaryEl = document.createElement('summary');
1316
+ summaryEl.textContent = 'Detalhes do evento';
794
1317
 
1318
+ const preEl = document.createElement('pre');
1319
+ preEl.className = 'wbc-event-console-detail';
1320
+ preEl.textContent = serialize(detail);
1321
+ detailsEl.append(summaryEl, preEl);
1322
+ return detailsEl;
1323
+ };
1324
+
1325
+ const createEventMetadata = (eventEntry) => {
1326
+ const metadataEl = document.createElement('dl');
1327
+ metadataEl.className = 'wbc-event-console-metadata';
1328
+ const metadataRows = [
1329
+ ['target', eventEntry.target],
1330
+ ['currentTarget', eventEntry.currentTarget || '—'],
1331
+ ['bubbles', eventEntry.bubbles],
1332
+ ['composed', eventEntry.composed],
1333
+ ['cancelable', eventEntry.cancelable],
1334
+ ];
1335
+ metadataRows.forEach(([label, value]) => {
1336
+ const term = document.createElement('dt');
1337
+ term.textContent = `${label}:`;
1338
+ const description = document.createElement('dd');
1339
+ description.textContent = String(value);
1340
+ metadataEl.append(term, description);
1341
+ });
1342
+ return metadataEl;
1343
+ };
1344
+
1345
+ const createEventItem = (eventEntry) => {
795
1346
  const item = document.createElement('li');
796
1347
  const name = document.createElement('span');
797
1348
  const target = document.createElement('span');
798
1349
 
799
1350
  name.className = 'wbc-event-console-event-name';
800
- name.textContent = event.type;
1351
+ name.textContent = `${eventEntry.eventType}${eventEntry.custom ? ' (customizado)' : ''}`;
801
1352
  target.className = 'wbc-event-console-target';
802
- target.textContent = ` — ${targetDescription || describeTarget(event.target || dispatchedBy)}`;
1353
+ target.textContent = ` — ${eventEntry.target}`;
1354
+ item.dataset.eventKind = eventEntry.custom ? 'custom' : 'native';
1355
+ item.dataset.eventTarget = eventEntry.target;
803
1356
  item.append(name, target);
804
1357
 
805
- if (event instanceof CustomEvent && event.detail !== undefined && event.detail !== null) {
806
- const detailsEl = document.createElement('details');
807
- detailsEl.className = 'wbc-event-console-details-container';
808
-
809
- const summaryEl = document.createElement('summary');
810
- summaryEl.textContent = 'payload';
811
-
812
- const preEl = document.createElement('pre');
813
- preEl.className = 'wbc-event-console-detail';
814
- preEl.textContent = serialize(event.detail);
815
-
816
- detailsEl.append(summaryEl, preEl);
817
- item.appendChild(detailsEl);
1358
+ if (eventEntry.detail !== undefined && eventEntry.detail !== null) {
1359
+ item.appendChild(createEventDetails(eventEntry.detail));
818
1360
  }
819
1361
 
820
- eventsList.prepend(item);
821
- applyFilter(); // Garante que novos eventos respeitem o filtro atual
1362
+ item.appendChild(createEventMetadata(eventEntry));
1363
+ if (eventEntry.composedPath.length > 0) {
1364
+ const pathEl = document.createElement('small');
1365
+ pathEl.className = 'wbc-event-console-path';
1366
+ pathEl.textContent = `path=${eventEntry.composedPath.join(' → ')}`;
1367
+ item.appendChild(pathEl);
1368
+ }
1369
+ return item;
1370
+ };
822
1371
 
1372
+ const trimEventsList = () => {
823
1373
  const maxEntries = 100;
824
1374
  while (eventsList.children.length > maxEntries) {
825
1375
  eventsList.lastElementChild?.remove();
826
1376
  }
1377
+ };
827
1378
 
828
- const isActive = eventsTabItem.getAttribute('is-active') === 'true';
829
- if (!isActive) {
830
- newEventsCount++;
831
- eventsTabItem.setAttribute('label', `Console (${newEventsCount})`);
1379
+ const addEventEntry = (event, dispatchedBy, targetDescription, metadata = {}) => {
1380
+ if (isPaused) return;
1381
+
1382
+ const eventEntry = createEventEntry(event, dispatchedBy, targetDescription, metadata);
1383
+ eventEntries.push(eventEntry);
1384
+ if (eventEntries.length > 100) eventEntries.shift();
1385
+ eventsList.prepend(createEventItem(eventEntry));
1386
+ applyFilter(); // Garante que novos eventos respeitem o filtro atual
1387
+ trimEventsList();
1388
+
1389
+ markConsoleEntry();
1390
+ };
1391
+
1392
+ const runtimeEntries = [];
1393
+ const createRuntimeEntryItem = (entry) => {
1394
+ const item = document.createElement('li');
1395
+ item.className = `wbc-runtime-entry wbc-runtime-entry--${entry.type}`;
1396
+ item.dataset.eventKind = 'runtime';
1397
+ item.dataset.eventTarget = entry.source || '';
1398
+ const heading = document.createElement('strong');
1399
+ heading.textContent = entry.type;
1400
+ item.appendChild(heading);
1401
+ if (entry.source) {
1402
+ const source = document.createElement('code');
1403
+ source.textContent = ` ${entry.source}${entry.line ? `:${entry.line}${entry.column ? `:${entry.column}` : ''}` : ''}`;
1404
+ item.appendChild(source);
832
1405
  }
1406
+ const body = document.createElement('span');
1407
+ body.textContent = ` ${(entry.args || []).map((value) => (typeof value === 'string' ? value : serialize(value))).join(' ')}`;
1408
+ item.appendChild(body);
1409
+ return item;
1410
+ };
1411
+
1412
+ const addRuntimeEntry = (entry) => {
1413
+ if (isPaused) return;
1414
+ runtimeEntries.push(entry);
1415
+ if (runtimeEntries.length > 100) runtimeEntries.shift();
1416
+ eventsList.prepend(createRuntimeEntryItem(entry));
1417
+ applyFilter();
1418
+ trimEventsList();
1419
+ markConsoleEntry();
833
1420
  };
1421
+ const clearConsole = () => {
1422
+ eventsList.replaceChildren();
1423
+ eventEntries.length = 0;
1424
+ runtimeEntries.length = 0;
1425
+ eventsTabItem.setAttribute('label', 'Console');
1426
+ eventsTabItem.removeAttribute('counter');
1427
+ newEventsCount = 0;
1428
+ };
1429
+ clearBtn.addEventListener('click', clearConsole);
834
1430
 
835
1431
  window.WBCActiveRecorders = window.WBCActiveRecorders || [];
836
1432
  const recorder = {
837
1433
  preview,
838
1434
  addEvent: addEventEntry,
839
1435
  };
840
- window.addEventListener('message', (event) => {
841
- if (!previewFrame || event.source !== previewFrame.contentWindow || !event.data?.type?.startsWith('wbc-preview-'))
1436
+
1437
+ const applyPreviewHeight = (height) => {
1438
+ if (activeViewport.width || hasManualPreviewHeight) return;
1439
+ const maxHeight = contentDiv.classList.contains('is-fullscreen') ? Infinity : window.innerHeight * 0.75;
1440
+ const targetHeight = Math.max(1, Math.min(height, maxHeight));
1441
+ const currentHeight = parseFloat(previewFrame.style.height) || 0;
1442
+ if (Math.abs(targetHeight - currentHeight) > 1) {
1443
+ previewFrame.style.height = `${targetHeight}px`;
1444
+ updatePreviewResizeA11y();
1445
+ }
1446
+ };
1447
+
1448
+ const isPreviewMessage = (event) =>
1449
+ previewFrame &&
1450
+ event.source === previewFrame.contentWindow &&
1451
+ event.data?.__playgroundChannelId === previewChannelId &&
1452
+ event.data?.type?.startsWith('wbc-preview-');
1453
+
1454
+ const handlePreviewEventMessage = (data) => {
1455
+ const bridgedEvent = data.custom
1456
+ ? new CustomEvent(data.eventType, {
1457
+ detail: data.detail,
1458
+ bubbles: data.bubbles,
1459
+ composed: data.composed,
1460
+ cancelable: data.cancelable,
1461
+ })
1462
+ : new Event(data.eventType, {
1463
+ bubbles: data.bubbles,
1464
+ composed: data.composed,
1465
+ cancelable: data.cancelable,
1466
+ });
1467
+ addEventEntry(bridgedEvent, previewFrame, data.target, data);
1468
+ };
1469
+
1470
+ const handlePreviewRuntimeMessage = (data) => {
1471
+ const runtimeTypes = ['log', 'warning', 'error', 'exception', 'unhandledrejection', 'component'];
1472
+ const runtimeType = runtimeTypes.includes(data.runtimeType) ? data.runtimeType : 'log';
1473
+ addRuntimeEntry({
1474
+ id: data.id,
1475
+ type: runtimeType,
1476
+ args: data.args || [],
1477
+ source: data.source,
1478
+ line: data.line,
1479
+ column: data.column,
1480
+ message: data.message,
1481
+ });
1482
+ };
1483
+
1484
+ const handlePreviewMessage = (event) => {
1485
+ if (!isPreviewMessage(event)) return;
1486
+ if (event.data.type === 'wbc-preview-exit-fullscreen') {
1487
+ closeFullscreen();
842
1488
  return;
1489
+ }
843
1490
  if (event.data.type === 'wbc-preview-height') {
844
- const maxHeight = contentDiv.classList.contains('is-fullscreen') ? Infinity : window.innerHeight * 0.75;
845
- previewFrame.style.height = `${Math.max(1, Math.min(event.data.height, maxHeight))}px`;
846
- } else if (event.data.type === 'wbc-preview-event') {
847
- const bridgedEvent = event.data.custom
848
- ? new CustomEvent(event.data.eventType, { detail: event.data.detail })
849
- : new Event(event.data.eventType);
850
- addEventEntry(bridgedEvent, previewFrame, event.data.target);
1491
+ applyPreviewHeight(event.data.height);
1492
+ return;
851
1493
  }
852
- });
1494
+ if (event.data.type === 'wbc-preview-event') {
1495
+ handlePreviewEventMessage(event.data);
1496
+ return;
1497
+ }
1498
+ if (event.data.type === 'wbc-preview-runtime') {
1499
+ handlePreviewRuntimeMessage(event.data);
1500
+ }
1501
+ };
1502
+
1503
+ window.addEventListener('message', handlePreviewMessage, { signal: exampleAbortController.signal });
1504
+ recorder.cleanup = () => {
1505
+ exampleAbortController.abort();
1506
+ recorder.cleanupNativeEvents?.();
1507
+ const recorderIndex = window.WBCActiveRecorders?.indexOf(recorder) ?? -1;
1508
+ if (recorderIndex >= 0) window.WBCActiveRecorders.splice(recorderIndex, 1);
1509
+ };
853
1510
  window.WBCActiveRecorders.push(recorder);
854
1511
  window.WBCRegisterNativeEventRecorder?.(recorder);
1512
+ activeExampleCleanups.add(recorder.cleanup);
1513
+
1514
+ let runAccessibilityAudit;
1515
+ let accessibilityAuditTimer;
1516
+ const scheduleAccessibilityAudit = () => {
1517
+ window.clearTimeout(accessibilityAuditTimer);
1518
+ accessibilityAuditTimer = window.setTimeout(() => runAccessibilityAudit?.(), 650);
1519
+ };
1520
+
1521
+ let vanillaFileTabs;
1522
+ function activateVanillaFile(target) {
1523
+ if (target === activeVanillaFile) return;
1524
+ activeVanillaFile = target;
1525
+ vanillaFileTabs?.querySelectorAll('.wbc-framework-file-tab').forEach((item) => {
1526
+ const active = item.dataset.vanillaFile === target;
1527
+ item.classList.toggle('is-active', active);
1528
+ item.setAttribute('aria-selected', String(active));
1529
+ });
1530
+ if (!editorApi) return;
1531
+ isSwitchingVanillaFile = true;
1532
+ editorApi.setLanguage?.(target);
1533
+ editorApi.setValue(vanillaSources[target]);
1534
+ isSwitchingVanillaFile = false;
1535
+ }
855
1536
 
856
- const setEditorValue = (value) => {
857
- editorState.value = value;
858
- editorApi?.setValue(value);
859
- applyEditorValue(value);
1537
+ const setEditorValue = (value, { recordHistory = true } = {}) => {
1538
+ const nextValue = String(value ?? '');
1539
+ if (nextValue === editorState.value) return;
1540
+ activateVanillaFile('html');
1541
+ isApplyingEditorValue = true;
1542
+ editorApi?.setValue(nextValue);
1543
+ isApplyingEditorValue = false;
1544
+ applyEditorValue(nextValue, { recordHistory });
860
1545
  };
861
1546
 
862
1547
  tabComponent.addEventListener('brTabChange', (event) => {
863
1548
  const activeTabId = event.detail.tabId;
864
- if (activeTabId !== 'code-tab') {
1549
+ if (activeTabId !== tabIds.code) {
865
1550
  eventsTabItem.setAttribute('label', 'Console');
866
1551
  newEventsCount = 0;
867
1552
  }
868
- if (frameworkTabItems.some((tab) => tab.getAttribute('tab-item-id') === activeTabId)) {
1553
+ if (frameworkTabItems.some((tab) => tab.id === activeTabId)) {
869
1554
  refreshFrameworkEditors();
870
1555
  }
871
1556
  });
872
1557
 
873
- codeTabItem.appendChild(editorWrapper);
1558
+ vanillaFileTabs = document.createElement('div');
1559
+ vanillaFileTabs.className = 'wbc-framework-file-tabs wbc-vanilla-file-tabs';
1560
+ vanillaFileTabs.setAttribute('role', 'tablist');
1561
+ vanillaFileTabs.setAttribute('aria-label', 'Arquivos HTML/CSS/JS');
1562
+ const vanillaFiles = [
1563
+ ['html', 'index.html'],
1564
+ ['css', 'index.css'],
1565
+ ['javascript', 'index.js'],
1566
+ ];
1567
+ vanillaFiles.forEach(([target, filename], index) => {
1568
+ const fileTab = document.createElement('button');
1569
+ fileTab.className = `wbc-framework-file-tab${index === 0 ? ' is-active' : ''}`;
1570
+ fileTab.type = 'button';
1571
+ fileTab.setAttribute('role', 'tab');
1572
+ fileTab.setAttribute('aria-selected', String(index === 0));
1573
+ fileTab.textContent = filename;
1574
+ fileTab.dataset.vanillaFile = target;
1575
+ fileTab.addEventListener('click', () => {
1576
+ if (target === activeVanillaFile) return;
1577
+ activateVanillaFile(target);
1578
+ refreshEditor();
1579
+ });
1580
+ vanillaFileTabs.appendChild(fileTab);
1581
+ });
1582
+
1583
+ codeTabItem.append(vanillaFileTabs, editorWrapper, diffPanel);
874
1584
  eventsTabItem.appendChild(eventsWrapper);
875
1585
 
876
1586
  // --- ACCESSIBILITY TAB ---
877
1587
  const a11yTabItem = document.createElement('br-tab-item');
878
1588
  a11yTabItem.setAttribute('label', 'Acessibilidade');
879
- a11yTabItem.setAttribute('icon', 'fas fa-universal-access');
880
1589
  a11yTabItem.setAttribute('icon-only', 'true');
881
- a11yTabItem.setAttribute('title', 'Acessibilidade');
882
- a11yTabItem.setAttribute('tab-item-id', 'a11y-tab');
1590
+ a11yTabItem.setAttribute('title', 'Auditoria de acessibilidade');
1591
+ a11yTabItem.id = tabIds.a11y;
1592
+ setTabIcon(a11yTabItem, 'fas fa-universal-access');
883
1593
 
884
1594
  const a11yWrapper = document.createElement('div');
885
1595
  a11yWrapper.className = 'wbc-example-a11y-wrapper';
@@ -899,25 +1609,32 @@ function createExampleElement(path, file, text, isExpanded = false, onOpen) {
899
1609
  a11yWrapper.append(a11yHeader, a11yResults);
900
1610
  a11yTabItem.appendChild(a11yWrapper);
901
1611
 
902
- const runAccessibilityAudit = async () => {
903
- if (!window.axe) {
904
- a11yResults.innerHTML =
905
- '<p class="text-danger mt-3">Axe-Core não está carregado. Verifique a conexão ou recarregue a página.</p>';
906
- return;
1612
+ const showA11yMessage = (className, message, iconClass) => {
1613
+ const paragraph = document.createElement('p');
1614
+ paragraph.className = className;
1615
+ if (iconClass) {
1616
+ const icon = document.createElement('i');
1617
+ icon.className = `${iconClass} mr-2`;
1618
+ icon.setAttribute('aria-hidden', 'true');
1619
+ paragraph.appendChild(icon);
907
1620
  }
1621
+ paragraph.appendChild(document.createTextNode(message));
1622
+ a11yResults.replaceChildren(paragraph);
1623
+ };
908
1624
 
909
- a11yResults.innerHTML =
910
- '<p class="mt-3"><i class="fas fa-spinner fa-spin mr-2"></i>Analisando acessibilidade...</p>';
1625
+ runAccessibilityAudit = async () => {
1626
+ showA11yMessage('mt-3', 'Analisando acessibilidade...', 'fas fa-spinner fa-spin');
911
1627
 
912
1628
  try {
913
1629
  const { axe, previewContent } = await getPreviewAxeContext(previewFrame);
914
1630
  const results = await axe.run(previewContent);
915
1631
 
916
1632
  if (results.violations.length === 0) {
917
- a11yResults.innerHTML =
918
- '<p class="text-success mt-3"><i class="fas fa-check-circle mr-2"></i>Nenhum problema de acessibilidade detectado!</p>';
1633
+ a11yTabItem.removeAttribute('counter');
1634
+ showA11yMessage('text-success mt-3', 'Nenhum problema de acessibilidade detectado!', 'fas fa-check-circle');
919
1635
  } else {
920
- a11yResults.innerHTML = '';
1636
+ a11yTabItem.setAttribute('counter', String(results.violations.length));
1637
+ a11yResults.replaceChildren();
921
1638
 
922
1639
  const violationsList = document.createElement('ul');
923
1640
  violationsList.className = 'wbc-a11y-violations-list mt-3';
@@ -934,7 +1651,8 @@ function createExampleElement(path, file, text, isExpanded = false, onOpen) {
934
1651
  impactBadge.textContent = violation.impact;
935
1652
 
936
1653
  const helpText = document.createElement('span');
937
- helpText.innerHTML = `<strong>${violation.help}</strong>`;
1654
+ helpText.textContent = violation.help;
1655
+ helpText.style.fontWeight = '700';
938
1656
 
939
1657
  title.append(helpText, impactBadge);
940
1658
 
@@ -955,21 +1673,23 @@ function createExampleElement(path, file, text, isExpanded = false, onOpen) {
955
1673
  a11yResults.appendChild(violationsList);
956
1674
  }
957
1675
  } catch (err) {
1676
+ a11yTabItem.setAttribute('counter', '1');
958
1677
  console.error(err);
959
- a11yResults.innerHTML = `<p class="text-danger mt-3">Erro ao executar a análise: ${err.message}</p>`;
1678
+ showA11yMessage(
1679
+ 'text-danger mt-3',
1680
+ `Erro ao executar a análise: ${err instanceof Error ? err.message : String(err)}`,
1681
+ );
960
1682
  }
961
1683
  };
962
1684
 
963
1685
  tabComponent.addEventListener('brTabChange', (event) => {
964
- if (event.detail.tabId === 'a11y-tab') runAccessibilityAudit();
965
- if (event.detail.tabId === 'code-tab') refreshEditor();
1686
+ if (event.detail.tabId === tabIds.a11y) runAccessibilityAudit();
1687
+ if (event.detail.tabId === tabIds.code) refreshEditor();
966
1688
  });
967
1689
 
968
1690
  tabComponent.append(
969
1691
  codeTabItem,
970
1692
  controlsTabItem,
971
- javascriptTabItem,
972
- cssTabItem,
973
1693
  eventsTabItem,
974
1694
  angularTabItem,
975
1695
  reactTabItem,
@@ -979,27 +1699,76 @@ function createExampleElement(path, file, text, isExpanded = false, onOpen) {
979
1699
  editorContainer.append(tabComponent);
980
1700
 
981
1701
  let controlsCssSource = '';
1702
+ let vanillaAssetsPreviewTimer;
1703
+ const persistDraft = () => {
1704
+ writePlaygroundDraft(path, file, {
1705
+ html: editorState.value,
1706
+ css: vanillaSources.css,
1707
+ javascript: vanillaSources.javascript,
1708
+ baselineHtml: comparisonBaseline,
1709
+ presetId: presetSelect.value || undefined,
1710
+ });
1711
+ };
982
1712
  const renderCurrentPreview = (source) => {
983
1713
  const managedStyle = controlsCssSource ? `<style data-playground-controls-css>${controlsCssSource}</style>` : '';
984
- renderExamplePreview(preview, `${source}${managedStyle}`, path === 'templates');
1714
+ const exampleStyle = vanillaSources.css.trim()
1715
+ ? `<style data-playground-css>${escapeInlineCode(vanillaSources.css, 'style')}</style>`
1716
+ : '';
1717
+ if (previewFrame) {
1718
+ previewFrame.classList.remove('wbc-preview-animate');
1719
+ void previewFrame.offsetWidth;
1720
+ previewFrame.classList.add('wbc-preview-animate');
1721
+ }
1722
+ renderExamplePreview(
1723
+ preview,
1724
+ `${source}${exampleStyle}${managedStyle}`,
1725
+ path === 'templates' || path === 'templates-ai',
1726
+ vanillaSources.javascript,
1727
+ previewChannelId,
1728
+ );
1729
+ updatePreviewResizeA11y();
985
1730
  };
986
1731
 
987
- const applyEditorValue = (source) => {
1732
+ const handleEditorChange = (source) => {
1733
+ if (isSwitchingVanillaFile) return;
1734
+ vanillaSources[activeVanillaFile] = String(source ?? '');
1735
+ if (activeVanillaFile === 'html') {
1736
+ if (!isApplyingEditorValue) applyEditorValue(source);
1737
+ return;
1738
+ }
1739
+ // CSS/JS recriam o preview com debounce para não reexecutar o script a cada tecla.
1740
+ window.clearTimeout(vanillaAssetsPreviewTimer);
1741
+ vanillaAssetsPreviewTimer = window.setTimeout(() => {
1742
+ renderCurrentPreview(editorState.value);
1743
+ scheduleAccessibilityAudit();
1744
+ persistDraft();
1745
+ }, 600);
1746
+ };
1747
+
1748
+ const applyEditorValue = (source, { recordHistory = true } = {}) => {
1749
+ source = String(source ?? '');
1750
+ vanillaSources.html = source;
1751
+ if (recordHistory) recordEditorHistory(source);
988
1752
  editorState.value = source;
989
1753
  updateFrameworkCode(source);
990
1754
  renderCurrentPreview(source);
1755
+ scheduleAccessibilityAudit();
991
1756
  renderedFilesContent[file] = { content: source.toLowerCase(), element: contentDiv };
992
- // The example script lives in the preview iframe and is recreated with it.
1757
+ persistDraft();
1758
+ updateHistoryActions();
1759
+ updateDiff(source);
1760
+ if (!isUpdatingFromControls) {
1761
+ controlsApi?.refresh?.();
1762
+ }
1763
+ // A remoção explícita ocorre antes da recriação do srcdoc para evitar que
1764
+ // o script específico do preset anterior permaneça no documento do iframe.
993
1765
  };
994
1766
 
995
1767
  const fullscreenBottomPanel = document.createElement('div');
996
1768
  fullscreenBottomPanel.className = 'wbc-example-fullscreen-bottom-panel';
997
1769
  fullscreenBottomPanel.appendChild(editorContainer);
998
1770
 
999
- preview.setAttribute('slot', 'target');
1000
- fullscreenBottomPanel.setAttribute('slot', 'target');
1001
- dropdown.appendChild(header);
1002
- contentDiv.appendChild(dropdown);
1771
+ contentDiv.append(header, presetDescription, preview, fullscreenBottomPanel);
1003
1772
 
1004
1773
  initializeExample = () => {
1005
1774
  previewFrame = document.createElement('iframe');
@@ -1007,8 +1776,16 @@ function createExampleElement(path, file, text, isExpanded = false, onOpen) {
1007
1776
  previewFrame.title = `Preview do exemplo ${file}`;
1008
1777
  previewFrame.dataset.path = path;
1009
1778
  previewFrame.setAttribute('loading', 'eager');
1010
- preview.appendChild(previewFrame);
1011
- renderCurrentPreview(text);
1779
+ previewFrame.addEventListener('load', () => {
1780
+ setPreviewReducedMotion(reducedMotionEnabled);
1781
+ setPreviewTheme(darkThemeEnabled);
1782
+ });
1783
+ previewViewport.append(previewFrame, previewWidthResizeHandle, previewHeightResizeHandle);
1784
+ preview.appendChild(previewViewport);
1785
+ preview.classList.add('wbc-example-preview--resizable');
1786
+ updatePreviewResizeA11y();
1787
+ renderCurrentPreview(editorState.value);
1788
+ scheduleAccessibilityAudit();
1012
1789
 
1013
1790
  const editorReady = window.WBCCodeEditorReady || Promise.resolve(window.WBCCodeEditor);
1014
1791
  editorReady.then(() => {
@@ -1016,7 +1793,7 @@ function createExampleElement(path, file, text, isExpanded = false, onOpen) {
1016
1793
  editorWrapper.textContent = '';
1017
1794
  editorApi = window.WBCCodeEditor.create({
1018
1795
  ariaLabel: `Código fonte do exemplo ${file}`,
1019
- onChange: applyEditorValue,
1796
+ onChange: handleEditorChange,
1020
1797
  parent: editorWrapper,
1021
1798
  value: editorState.value,
1022
1799
  language: 'html',
@@ -1035,7 +1812,7 @@ function createExampleElement(path, file, text, isExpanded = false, onOpen) {
1035
1812
  parent: editorContainer,
1036
1813
  value: code.textContent || '',
1037
1814
  language: getFrameworkEditorLanguage(framework),
1038
- readOnly: true,
1815
+ readOnly: tab.dataset.editable !== 'true',
1039
1816
  });
1040
1817
  frameworkEditors.set(tab, editor);
1041
1818
  tab.querySelectorAll('.wbc-framework-file-tab').forEach((fileTab) => {
@@ -1050,7 +1827,7 @@ function createExampleElement(path, file, text, isExpanded = false, onOpen) {
1050
1827
 
1051
1828
  customElements.whenDefined('br-tab').then(() => {
1052
1829
  requestAnimationFrame(async () => {
1053
- await tabComponent.setActiveTab?.('code-tab');
1830
+ await tabComponent.setActiveTab?.(tabIds.code);
1054
1831
  refreshEditor();
1055
1832
  });
1056
1833
  });
@@ -1065,13 +1842,27 @@ function createExampleElement(path, file, text, isExpanded = false, onOpen) {
1065
1842
  setCss: (value) => {
1066
1843
  controlsCssSource = value;
1067
1844
  renderCurrentPreview(getEditorValue());
1845
+ scheduleAccessibilityAudit();
1068
1846
  },
1069
1847
  setHtml: (value) => {
1070
- setEditorValue(value);
1848
+ isUpdatingFromControls = true;
1849
+ try {
1850
+ setEditorValue(value);
1851
+ } finally {
1852
+ isUpdatingFromControls = false;
1853
+ }
1071
1854
  },
1855
+ }).then((api) => {
1856
+ controlsApi = api;
1072
1857
  });
1073
1858
  };
1074
1859
 
1860
+ queueMicrotask(() => {
1861
+ if (isInitialized) return;
1862
+ initializeExample();
1863
+ isInitialized = true;
1864
+ });
1865
+
1075
1866
  renderedFilesContent[file] = { content: text.toLowerCase(), element: contentDiv };
1076
1867
 
1077
1868
  return contentDiv;
@@ -1083,7 +1874,13 @@ function createComponentTags(metadata) {
1083
1874
  wrapper.setAttribute('aria-label', 'Classificação do componente');
1084
1875
  const colors = { stable: 'var(--success)', beta: '#ffcd07', deprecated: 'var(--danger)' };
1085
1876
  const labels = { stable: 'Estável', beta: 'Em testes', deprecated: 'Depreciado' };
1086
- (metadata?.categories || []).forEach((category) => {
1877
+ const categories = Array.from(
1878
+ new Set([
1879
+ ...(Array.isArray(metadata?.categories) ? metadata.categories : []),
1880
+ ...(metadata?.category ? [metadata.category] : []),
1881
+ ]),
1882
+ ).filter((category) => typeof category === 'string' && category.trim());
1883
+ categories.forEach((category) => {
1087
1884
  const tag = document.createElement('br-tag');
1088
1885
  tag.setAttribute('label', category);
1089
1886
  tag.setAttribute('bg-color', 'var(--interactive)');
@@ -1096,7 +1893,7 @@ function createComponentTags(metadata) {
1096
1893
  statusTag.setAttribute('bg-color', colors[status] || colors.stable);
1097
1894
  statusTag.className = `wbc-component-status wbc-component-status--${status}`;
1098
1895
  if (status === 'beta') {
1099
- statusTag.style.setProperty('--color-dark', '#333');
1896
+ statusTag.classList.add('wbc-component-status--beta');
1100
1897
  const tooltip = document.createElement('br-tooltip');
1101
1898
  tooltip.setAttribute('position', 'top');
1102
1899
  tooltip.setAttribute('aria-label', 'Status: Em testes');
@@ -1113,6 +1910,42 @@ function createComponentTags(metadata) {
1113
1910
  return wrapper;
1114
1911
  }
1115
1912
 
1913
+ function createComponentHeading(metadata) {
1914
+ const heading = document.createElement('h1');
1915
+ heading.className = 'wbc-component-title';
1916
+ heading.textContent = metadata?.name || 'Componente';
1917
+ return heading;
1918
+ }
1919
+
1920
+ function getPresetSource(preset) {
1921
+ if (typeof preset?.source === 'string') return preset.source;
1922
+ return preset?.source?.text || '';
1923
+ }
1924
+
1925
+ function getSharedExampleState(path, file) {
1926
+ const sharedState = window.SHARED_STATE;
1927
+ if (sharedState?.p !== path || sharedState?.f !== file) return null;
1928
+
1929
+ const { presetId } = getHashState();
1930
+ if (presetId && sharedState.presetId && presetId !== sharedState.presetId) return null;
1931
+ return sharedState;
1932
+ }
1933
+
1934
+ function getPresetForExample(path, example, presets) {
1935
+ const { file, presetId } = getHashState();
1936
+ const sharedState = getSharedExampleState(path, example.id);
1937
+ const candidateIds = [];
1938
+
1939
+ if (file === example.id && presetId) candidateIds.push(presetId);
1940
+ if (sharedState?.presetId) candidateIds.push(sharedState.presetId);
1941
+ candidateIds.push(example.defaultPreset, ...example.presets);
1942
+
1943
+ return candidateIds
1944
+ .filter(Boolean)
1945
+ .map((id) => presets.find((preset) => preset.id === id))
1946
+ .find((preset) => preset && example.presets.includes(preset.id) && getPresetSource(preset));
1947
+ }
1948
+
1116
1949
  function getInitialExampleFile(path, files) {
1117
1950
  const requestedFile = getRequestedExampleFile();
1118
1951
  if (files.includes(requestedFile)) return { initialFile: requestedFile, requestedFile };
@@ -1120,111 +1953,219 @@ function getInitialExampleFile(path, files) {
1120
1953
  return { initialFile: 'default', requestedFile };
1121
1954
  }
1122
1955
 
1123
- function createExamplesList(path, results, initialFile) {
1956
+ function createExamplesList(path, results, presets = [], exampleConfigs = [], initialFile = 'default') {
1124
1957
  let sharedElementToScroll = null;
1958
+ let initialPresetId = '';
1125
1959
  const examples = document.createElement('br-list');
1126
1960
  examples.className = 'wbc-examples-list';
1127
1961
  examples.setAttribute('list-role', 'group');
1128
1962
  examples.setAttribute('divider', '');
1963
+ const configById = new Map(exampleConfigs.map((example) => [example.id, example]));
1129
1964
  results.sort((a, b) => Number(b.file === 'default') - Number(a.file === 'default'));
1130
- results.forEach(({ file, text }, index) => {
1965
+ results.forEach(({ file, text }) => {
1966
+ const config = configById.get(file);
1967
+ const availableIds = Array.isArray(config?.presets) ? new Set(config.presets) : new Set();
1968
+ const availablePresets = presets.filter(({ id }) => availableIds.has(id));
1969
+ const example = {
1970
+ id: file,
1971
+ presets: [...availableIds],
1972
+ defaultPreset: config?.defaultPreset,
1973
+ };
1974
+ const selectedPreset = getPresetForExample(path, example, availablePresets);
1975
+ const fallbackPreset = availablePresets.find(
1976
+ (preset) => preset.id === config?.defaultPreset && getPresetSource(preset),
1977
+ );
1978
+ const selectedPresetId =
1979
+ selectedPreset?.id || fallbackPreset?.id || availablePresets.find((preset) => getPresetSource(preset))?.id || '';
1131
1980
  const element = createExampleElement(
1132
1981
  path,
1133
1982
  file,
1134
1983
  text,
1135
- file === initialFile || (!initialFile && index === 0),
1136
- (openedFile) => {
1137
- const hash = getExampleHash(openedFile);
1138
- if (window.location.hash !== hash) {
1139
- window.history.replaceState({}, '', `${window.location.pathname}${window.location.search}${hash}`);
1140
- }
1141
- examples.querySelectorAll('br-dropdown').forEach((other) => {
1142
- if (other !== element.querySelector('br-dropdown') && other.isOpen) other.isOpen = false;
1143
- });
1144
- },
1984
+ availablePresets.map(({ source, ...preset }) => ({ ...preset, source: source?.text ?? null })),
1985
+ selectedPresetId,
1986
+ config?.label || file,
1145
1987
  );
1988
+ element.dataset.defaultPreset =
1989
+ fallbackPreset?.id || availablePresets.find((preset) => getPresetSource(preset))?.id || '';
1146
1990
  examples.appendChild(element);
1147
- if (window.SHARED_STATE?.p === path && window.SHARED_STATE?.f === file) sharedElementToScroll = element;
1148
- });
1149
- return { examples, sharedElementToScroll };
1150
- }
1151
-
1152
- function openInitialDropdown(examples, initialFile) {
1153
- const initialDropdown = initialFile
1154
- ? examples.querySelector(`[data-example-file="${CSS.escape(initialFile)}"] br-dropdown`)
1155
- : null;
1156
- if (!initialDropdown) return;
1157
- customElements.whenDefined('br-dropdown').then(() => {
1158
- initialDropdown.isOpen = false;
1159
- initialDropdown.open();
1991
+ if (file === initialFile) initialPresetId = selectedPresetId;
1992
+ if (getSharedExampleState(path, file)) sharedElementToScroll = element;
1160
1993
  });
1994
+ return { examples, initialPresetId, sharedElementToScroll };
1161
1995
  }
1162
1996
 
1163
1997
  function scrollToInitialExample(examples, requestedFile, sharedElementToScroll) {
1164
1998
  const hashElement = requestedFile
1165
1999
  ? examples.querySelector(`[data-example-file="${CSS.escape(requestedFile)}"]`)
1166
2000
  : null;
1167
- if (hashElement) setTimeout(() => hashElement.scrollIntoView({ behavior: 'smooth', block: 'center' }), 500);
2001
+ if (hashElement)
2002
+ setTimeout(() => hashElement.scrollIntoView({ behavior: getScrollBehavior(), block: 'center' }), 500);
1168
2003
  if (sharedElementToScroll) {
1169
2004
  setTimeout(() => {
1170
- sharedElementToScroll.scrollIntoView({ behavior: 'smooth', block: 'center' });
2005
+ sharedElementToScroll.scrollIntoView({ behavior: getScrollBehavior(), block: 'center' });
1171
2006
  sharedElementToScroll.classList.add('wbc-example-shared-highlight');
1172
2007
  }, 500);
1173
2008
  }
1174
2009
  }
1175
2010
 
1176
- function renderLoadedPage(path, files, results) {
2011
+ function renderLoadedPage(path, examples, results, presets = []) {
1177
2012
  const metadata = window.MENU_ITEMS?.find((item) => item.path === path);
1178
- if (metadata) CONTENT_ELEMENT.appendChild(createComponentTags(metadata));
1179
- const { initialFile, requestedFile } = getInitialExampleFile(path, files);
1180
- const { examples, sharedElementToScroll } = createExamplesList(path, results, initialFile);
1181
- CONTENT_ELEMENT.appendChild(examples);
1182
- openInitialDropdown(examples, initialFile);
1183
- if (initialFile && files.includes(initialFile) && window.location.hash !== getExampleHash(initialFile)) {
1184
- window.history.replaceState(
1185
- {},
1186
- '',
1187
- `${window.location.pathname}${window.location.search}${getExampleHash(initialFile)}`,
1188
- );
2013
+ if (metadata) {
2014
+ CONTENT_ELEMENT.appendChild(createComponentHeading(metadata));
2015
+ CONTENT_ELEMENT.appendChild(createComponentTags(metadata));
2016
+ }
2017
+ const exampleIds = examples.map(({ id }) => id);
2018
+ const { initialFile, requestedFile } = getInitialExampleFile(path, exampleIds);
2019
+ const {
2020
+ examples: examplesList,
2021
+ initialPresetId,
2022
+ sharedElementToScroll,
2023
+ } = createExamplesList(path, results, presets, examples, initialFile);
2024
+ CONTENT_ELEMENT.appendChild(examplesList);
2025
+ if (initialFile && exampleIds.includes(initialFile)) {
2026
+ const targetHash = getExampleHash(initialFile, initialPresetId || undefined);
2027
+ if (window.location.hash !== targetHash) {
2028
+ const url = new URL(window.location.href);
2029
+ url.hash = targetHash;
2030
+ const currentState = window.history.state;
2031
+ const nextState = currentState && typeof currentState === 'object' ? currentState : {};
2032
+ window.history.replaceState(nextState, '', url.href);
2033
+ }
1189
2034
  }
1190
- scrollToInitialExample(examples, requestedFile, sharedElementToScroll);
2035
+ scrollToInitialExample(examplesList, requestedFile, sharedElementToScroll);
1191
2036
  currentLoadedPath = path;
1192
2037
  }
1193
2038
 
1194
- function loadPage(path, files) {
2039
+ function normalizePageExample(example, presets) {
2040
+ const isLegacyExample = typeof example === 'string';
2041
+ const exampleConfig = isLegacyExample ? {} : example;
2042
+ const exampleId = isLegacyExample ? example : exampleConfig.id;
2043
+ const examplePresetIds = Array.isArray(exampleConfig.presets) ? exampleConfig.presets : [];
2044
+ const requestedPresetId = isLegacyExample ? exampleId : exampleConfig.defaultPreset;
2045
+ const fallbackPreset =
2046
+ presets.find(({ id }) => id === requestedPresetId) ??
2047
+ presets.find(({ id }) => id === `example-${exampleId}`) ??
2048
+ presets.find(({ id }) => examplePresetIds.includes(id)) ??
2049
+ presets[0];
2050
+
2051
+ return {
2052
+ ...exampleConfig,
2053
+ id: exampleId,
2054
+ presets: examplePresetIds.length > 0 ? examplePresetIds : fallbackPreset ? [fallbackPreset.id] : [],
2055
+ defaultPreset: exampleConfig.defaultPreset || fallbackPreset?.id,
2056
+ };
2057
+ }
2058
+
2059
+ function normalizePageExamples(examples, presets) {
2060
+ return examples.map((example) => normalizePageExample(example, presets));
2061
+ }
2062
+
2063
+ const PLAYGROUND_SOURCE_FETCH_ATTEMPTS = 4;
2064
+
2065
+ function waitForPlaygroundSourceRetry(attempt) {
2066
+ return new Promise((resolve) => setTimeout(resolve, attempt * 150));
2067
+ }
2068
+
2069
+ async function fetchPlaygroundSource(path, source) {
2070
+ if (!source) throw new Error(`Fonte ausente para ${path}`);
2071
+
2072
+ let lastError;
2073
+ for (let attempt = 1; attempt <= PLAYGROUND_SOURCE_FETCH_ATTEMPTS; attempt += 1) {
2074
+ try {
2075
+ const response = await fetch(`${getBaseUrl()}/pages/components/${path}/${source}`, { cache: 'no-store' });
2076
+ if (!response.ok) throw new Error(`HTTP ${response.status}`);
2077
+ return stripDevServerConnector(await response.text());
2078
+ } catch (error) {
2079
+ lastError = error;
2080
+ if (attempt < PLAYGROUND_SOURCE_FETCH_ATTEMPTS) await waitForPlaygroundSourceRetry(attempt);
2081
+ }
2082
+ }
2083
+
2084
+ throw lastError;
2085
+ }
2086
+
2087
+ function loadPage(path, examples, presets = [], baseScript = '', baseStyle = '') {
2088
+ const loadGeneration = ++pageLoadGeneration;
2089
+ cleanupExamples();
1195
2090
  window.WBCActiveRecorders = [];
1196
2091
  CONTENT_ELEMENT.innerHTML = '';
1197
2092
  renderedFilesContent = {};
1198
2093
  if (COMPONENTS_FILTER) COMPONENTS_FILTER.value = ''; // Limpa o campo de busca ao trocar de página
1199
- if (CLEAR_COMPONENTS_FILTER) CLEAR_COMPONENTS_FILTER.style.display = 'none'; // Esconde o botão de limpar
1200
-
1201
- const baseUrl = getBaseUrl();
1202
- const promises = files.map((file) => {
1203
- if (window.SHARED_STATE && window.SHARED_STATE.p === path && window.SHARED_STATE.f === file) {
1204
- return Promise.resolve({ file, text: stripDevServerConnector(window.SHARED_STATE.h) });
2094
+ if (CLEAR_COMPONENTS_FILTER) CLEAR_COMPONENTS_FILTER.hidden = true;
2095
+
2096
+ const pageExamples = normalizePageExamples(examples, presets);
2097
+ const presetSources = new Map();
2098
+ const uniquePresetSources = [...new Set(presets.map(({ source }) => source).filter(Boolean))];
2099
+ const presetPromises = uniquePresetSources.map((source) =>
2100
+ fetchPlaygroundSource(path, source)
2101
+ .then((text) => {
2102
+ presetSources.set(source, text);
2103
+ })
2104
+ .catch((error) => {
2105
+ console.warn(`Não foi possível carregar o preset ${path}/${source}:`, error);
2106
+ }),
2107
+ );
2108
+ // JS e CSS do preset ficam em arquivos irmãos do HTML; `index.js`/`index.css`
2109
+ // valem para todos os presets do componente e vêm antes do arquivo do preset.
2110
+ const assetSources = new Map();
2111
+ const uniqueAssetSources = [
2112
+ ...new Set([baseScript, baseStyle, ...presets.flatMap(({ script, style }) => [script, style])].filter(Boolean)),
2113
+ ];
2114
+ const assetPromises = uniqueAssetSources.map((source) =>
2115
+ fetchPlaygroundSource(path, source)
2116
+ .then((text) => {
2117
+ assetSources.set(source, text.trim());
2118
+ })
2119
+ .catch((error) => {
2120
+ console.warn(`Não foi possível carregar ${path}/${source}:`, error);
2121
+ }),
2122
+ );
2123
+ const joinAssets = (...sources) =>
2124
+ sources
2125
+ .map((source) => assetSources.get(source))
2126
+ .filter(Boolean)
2127
+ .join('\n\n');
2128
+ const promises = pageExamples.map((example) => {
2129
+ const selectedPreset = getPresetForExample(path, example, presets);
2130
+ const source = getPresetSource(selectedPreset);
2131
+ const sharedState = getSharedExampleState(path, example.id);
2132
+ if (sharedState) {
2133
+ return Promise.resolve({ file: example.id, text: stripDevServerConnector(window.SHARED_STATE.h) });
1205
2134
  }
1206
- return fetch(`${baseUrl}/pages/components/${path}/${file}.html`).then((response) =>
1207
- response.text().then((text) => ({ file, text: stripDevServerConnector(text) })),
1208
- );
2135
+ return fetchPlaygroundSource(path, source).then((text) => ({ file: example.id, text }));
1209
2136
  });
1210
2137
 
1211
- Promise.all(promises)
1212
- .then((results) => renderLoadedPage(path, files, results))
2138
+ Promise.all([Promise.all(promises), Promise.all(presetPromises), Promise.all(assetPromises)])
2139
+ .then(([results]) => {
2140
+ if (loadGeneration !== pageLoadGeneration) return;
2141
+ const loadedPresets = presets.map((preset) => ({
2142
+ ...preset,
2143
+ source: presetSources.has(preset.source)
2144
+ ? { text: presetSources.get(preset.source), path: preset.source }
2145
+ : null,
2146
+ javascript: joinAssets(baseScript, preset.script),
2147
+ css: joinAssets(baseStyle, preset.style),
2148
+ }));
2149
+ renderLoadedPage(path, pageExamples, results, loadedPresets);
2150
+ })
1213
2151
  .catch((error) => {
1214
2152
  console.log('Erro ao carregar a página:', error);
1215
2153
  });
1216
2154
  }
1217
2155
 
1218
2156
  function loadMarkdown(path) {
2157
+ const loadGeneration = ++pageLoadGeneration;
2158
+ cleanupExamples();
1219
2159
  CONTENT_ELEMENT.innerHTML = '';
1220
2160
  renderedFilesContent = {};
1221
2161
  if (COMPONENTS_FILTER) COMPONENTS_FILTER.value = ''; // Limpa o campo de busca ao trocar de página
1222
- if (CLEAR_COMPONENTS_FILTER) CLEAR_COMPONENTS_FILTER.style.display = 'none'; // Esconde o botão de limpar
2162
+ if (CLEAR_COMPONENTS_FILTER) CLEAR_COMPONENTS_FILTER.hidden = true;
1223
2163
 
1224
2164
  const baseUrl = getBaseUrl();
1225
2165
  fetch(`${baseUrl}/assets/stencil-generated-docs/${path}.md`)
1226
2166
  .then((response) => response.text())
1227
2167
  .then((text) => {
2168
+ if (loadGeneration !== pageLoadGeneration) return;
1228
2169
  const contentDiv = document.createElement('div');
1229
2170
  contentDiv.classList.add('file', 'mt-2', 'mb-5');
1230
2171
  const parsedMarkdown = typeof markdownParser?.parse === 'function' ? markdownParser.parse(text) : text;
@@ -1280,26 +2221,26 @@ function filterContent() {
1280
2221
  const rows = element.querySelectorAll('table tr');
1281
2222
  rows.forEach((row, index) => {
1282
2223
  if (index === 0) {
1283
- row.style.display = '';
2224
+ row.hidden = false;
1284
2225
  } else {
1285
2226
  const rowText = row.textContent
1286
2227
  .toLowerCase()
1287
2228
  .normalize('NFD')
1288
2229
  .replace(/[\u0300-\u036f]/g, '');
1289
- row.style.display = rowText.includes(normalizedFilterValue) ? '' : 'none';
2230
+ row.hidden = !rowText.includes(normalizedFilterValue);
1290
2231
  }
1291
2232
  });
1292
2233
  } else if (
1293
2234
  normalizedFilterValue &&
1294
2235
  (combinedContent.includes(normalizedFilterValue) || normalizedTitleText.includes(normalizedFilterValue))
1295
2236
  ) {
1296
- element.style.display = ''; // Exibe o elemento se o conteúdo combinado inclui o valor filtrado
2237
+ element.hidden = false;
1297
2238
  } else {
1298
- element.style.display = normalizedFilterValue ? 'none' : ''; // Oculta se não houver filtro
2239
+ element.hidden = Boolean(normalizedFilterValue);
1299
2240
  }
1300
2241
  });
1301
2242
 
1302
- if (CLEAR_COMPONENTS_FILTER) CLEAR_COMPONENTS_FILTER.style.display = filterValue ? 'block' : 'none';
2243
+ if (CLEAR_COMPONENTS_FILTER) CLEAR_COMPONENTS_FILTER.hidden = !filterValue;
1303
2244
  }
1304
2245
 
1305
2246
  function processMenuItems(menuItems, menuBody, currentPath) {
@@ -1314,7 +2255,8 @@ function processMenuItems(menuItems, menuBody, currentPath) {
1314
2255
  link.active = true;
1315
2256
  link.classList.add('active');
1316
2257
  }
1317
- if (Array.isArray(page.files)) loadPage(page.path, page.files);
2258
+ if (Array.isArray(page.examples))
2259
+ loadPage(page.path, page.examples, page.presets, page.baseScript, page.baseStyle);
1318
2260
  }
1319
2261
  });
1320
2262
  }
@@ -1336,6 +2278,20 @@ function processStaticItems(staticItems, menuBody, currentPath) {
1336
2278
  });
1337
2279
  }
1338
2280
 
2281
+ function requestActiveMenuScroll() {
2282
+ if (typeof window.scrollActiveMenuItemIntoView === 'function') {
2283
+ window.scrollActiveMenuItemIntoView();
2284
+ }
2285
+ }
2286
+
2287
+ function syncRenderedPresetFromLocation() {
2288
+ const { file, presetId } = getHashState();
2289
+ const targetFile = file || 'default';
2290
+
2291
+ const example = CONTENT_ELEMENT?.querySelector(`[data-example-file="${CSS.escape(targetFile)}"]`);
2292
+ example?._applyPresetFromUrl?.(presetId);
2293
+ }
2294
+
1339
2295
  // Liga eventos apenas se os elementos existirem
1340
2296
  if (COMPONENTS_FILTER) {
1341
2297
  COMPONENTS_FILTER.addEventListener('input', filterContent);
@@ -1354,6 +2310,8 @@ function loadPageFromURL() {
1354
2310
 
1355
2311
  // Evita recarregar a mesma rota em chamadas repetidas
1356
2312
  if (currentPath === currentLoadedPath) {
2313
+ syncRenderedPresetFromLocation();
2314
+ requestActiveMenuScroll();
1357
2315
  return;
1358
2316
  }
1359
2317
 
@@ -1372,9 +2330,9 @@ function loadPageFromURL() {
1372
2330
  processStaticItems(window.MENU_STATIC_ITEMS, menuBody, currentPath);
1373
2331
 
1374
2332
  if (currentPath.trim().length === 0 && menuItems.length > 0) {
1375
- const firstPage = menuItems.find((p) => p?.path && Array.isArray(p.files));
2333
+ const firstPage = menuItems.find((p) => p?.path && Array.isArray(p.examples));
1376
2334
  if (firstPage) {
1377
- loadPage(firstPage.path, firstPage.files);
2335
+ loadPage(firstPage.path, firstPage.examples, firstPage.presets, firstPage.baseScript, firstPage.baseStyle);
1378
2336
  const firstLink = menuBody
1379
2337
  ? Array.from(menuBody.children).find((item) => item.getAttribute('href') === `/${firstPage.path}`)
1380
2338
  : null;
@@ -1385,6 +2343,8 @@ function loadPageFromURL() {
1385
2343
  window.history.pushState({}, '', `${baseUrl}/${firstPage.path}`);
1386
2344
  }
1387
2345
  }
2346
+
2347
+ requestActiveMenuScroll();
1388
2348
  }
1389
2349
 
1390
2350
  // Aguarda DOM e dados do menu antes de tentar carregar a rota atual
@@ -1422,15 +2382,18 @@ if (document.readyState === 'loading') {
1422
2382
  // Garante atualização ao navegar com back/forward
1423
2383
  window.addEventListener('popstate', () => bootstrapRouting());
1424
2384
 
2385
+ // O gerador do playground atualiza o índice enquanto o servidor permanece aberto.
2386
+ // Invalida a rota carregada para que os presets do JSON sejam lidos novamente.
2387
+ window.addEventListener('wbcMenuItemsUpdated', () => {
2388
+ currentLoadedPath = null;
2389
+ bootstrapRouting();
2390
+ });
2391
+
1425
2392
  window.addEventListener('hashchange', () => {
2393
+ syncRenderedPresetFromLocation();
1426
2394
  const file = getRequestedExampleFile();
1427
2395
  const example = file ? document.querySelector(`br-item[data-example-file="${CSS.escape(file)}"]`) : null;
1428
2396
  if (!example) return;
1429
2397
 
1430
- const dropdown = example.querySelector('br-dropdown');
1431
- if (dropdown) dropdown.isOpen = true;
1432
- document.querySelectorAll('.wbc-example-dropdown').forEach((other) => {
1433
- if (other !== dropdown) other.isOpen = false;
1434
- });
1435
- setTimeout(() => example.scrollIntoView({ behavior: 'smooth', block: 'center' }), 100);
2398
+ setTimeout(() => example.scrollIntoView({ behavior: getScrollBehavior(), block: 'center' }), 100);
1436
2399
  });