@shortfuse/materialdesignweb 0.8.0 → 0.9.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 (394) hide show
  1. package/README.md +32 -24
  2. package/bin/mdw-css.js +1 -1
  3. package/components/Badge.js +12 -5
  4. package/components/Body.js +3 -0
  5. package/components/BottomAppBar.js +1 -8
  6. package/components/BottomSheet.js +424 -0
  7. package/components/Box.js +11 -49
  8. package/components/Button.js +61 -82
  9. package/components/Card.js +56 -61
  10. package/components/Checkbox.js +7 -25
  11. package/components/CheckboxIcon.js +10 -28
  12. package/components/Chip.js +13 -11
  13. package/components/Dialog.js +49 -98
  14. package/components/Display.js +55 -0
  15. package/components/Fab.js +83 -17
  16. package/components/FabContainer.js +48 -0
  17. package/components/FilterChip.js +34 -32
  18. package/components/Grid.js +176 -0
  19. package/components/Headline.js +5 -28
  20. package/components/Icon.js +54 -69
  21. package/components/IconButton.js +71 -120
  22. package/components/Input.js +669 -83
  23. package/components/InputChip.js +161 -0
  24. package/components/Label.js +3 -0
  25. package/components/List.js +1 -5
  26. package/components/ListItem.js +39 -23
  27. package/components/ListOption.js +79 -62
  28. package/components/Listbox.js +19 -10
  29. package/components/Menu.js +8 -18
  30. package/components/MenuItem.js +25 -26
  31. package/components/NavBar.js +53 -19
  32. package/components/NavDrawer.js +15 -15
  33. package/components/NavDrawerItem.js +2 -4
  34. package/components/NavItem.js +40 -33
  35. package/components/NavRail.js +23 -21
  36. package/components/NavRailItem.js +5 -2
  37. package/components/Page.js +105 -0
  38. package/components/Pane.js +18 -0
  39. package/components/Popup.js +17 -8
  40. package/components/Radio.js +2 -5
  41. package/components/RadioIcon.js +10 -14
  42. package/components/Ripple.js +11 -7
  43. package/components/Root.js +209 -0
  44. package/components/Scrim.js +87 -0
  45. package/components/Search.js +12 -20
  46. package/components/SegmentedButton.js +33 -36
  47. package/components/SegmentedButtonGroup.js +9 -3
  48. package/components/Select.js +6 -7
  49. package/components/Shape.js +5 -65
  50. package/components/SideSheet.js +308 -0
  51. package/components/Slider.js +71 -34
  52. package/components/Snackbar.js +22 -16
  53. package/components/SnackbarContainer.js +42 -0
  54. package/components/Surface.js +15 -10
  55. package/components/Switch.js +3 -16
  56. package/components/SwitchIcon.js +40 -32
  57. package/components/Tab.js +57 -38
  58. package/components/TabContent.js +1 -0
  59. package/components/TabList.js +60 -32
  60. package/components/TabPanel.js +1 -1
  61. package/components/Table.js +116 -0
  62. package/components/TextArea.js +16 -15
  63. package/components/Title.js +4 -9
  64. package/components/Tooltip.js +43 -21
  65. package/components/TopAppBar.js +56 -78
  66. package/constants/shapes.js +36 -0
  67. package/constants/typography.js +127 -0
  68. package/core/Composition.js +354 -192
  69. package/core/CompositionAdapter.js +11 -12
  70. package/core/CustomElement.js +588 -236
  71. package/core/css.js +117 -12
  72. package/core/customTypes.js +120 -25
  73. package/core/dom.js +17 -11
  74. package/core/jsonMergePatch.js +12 -10
  75. package/core/observe.js +298 -253
  76. package/core/optimizations.js +9 -9
  77. package/core/template.js +14 -57
  78. package/dist/index.min.js +85 -115
  79. package/dist/index.min.js.map +4 -4
  80. package/dist/meta.json +1 -1
  81. package/dom/HTMLOptionsCollectionProxy.js +106 -0
  82. package/{theming/themableMixinLoader.js → loaders/palette.js} +4 -3
  83. package/loaders/theme.js +12 -0
  84. package/mixins/AriaReflectorMixin.js +53 -13
  85. package/mixins/AriaToolbarMixin.js +3 -0
  86. package/mixins/ControlMixin.js +76 -33
  87. package/mixins/DelegatesFocusMixin.js +54 -0
  88. package/mixins/DensityMixin.js +2 -2
  89. package/mixins/ElevationMixin.js +62 -0
  90. package/mixins/FlexableMixin.js +66 -37
  91. package/mixins/FormAssociatedMixin.js +60 -8
  92. package/mixins/HyperlinkMixin.js +66 -0
  93. package/mixins/InputMixin.js +205 -32
  94. package/mixins/KeyboardNavMixin.js +8 -6
  95. package/mixins/NavigationListenerMixin.js +33 -0
  96. package/mixins/PopupMixin.js +176 -208
  97. package/mixins/ResizeObserverMixin.js +16 -4
  98. package/mixins/RippleMixin.js +8 -6
  99. package/mixins/ScrollListenerMixin.js +1 -1
  100. package/mixins/SemiStickyMixin.js +44 -98
  101. package/mixins/ShapeMaskedMixin.js +117 -0
  102. package/mixins/ShapeMixin.js +22 -204
  103. package/mixins/StateMixin.js +70 -34
  104. package/mixins/TextFieldMixin.js +107 -143
  105. package/mixins/ThemableMixin.js +44 -56
  106. package/mixins/TooltipTriggerMixin.js +291 -359
  107. package/mixins/TouchTargetMixin.js +1 -1
  108. package/mixins/TypographyMixin.js +121 -0
  109. package/package.json +110 -74
  110. package/services/rtl.js +10 -0
  111. package/services/svgAlias.js +17 -0
  112. package/{theming/index.js → services/theme.js} +24 -174
  113. package/types/bin/mdw-css.d.ts +3 -0
  114. package/types/bin/mdw-css.d.ts.map +1 -0
  115. package/types/components/Badge.d.ts +39 -0
  116. package/types/components/Badge.d.ts.map +1 -0
  117. package/types/components/Body.d.ts +29 -0
  118. package/types/components/Body.d.ts.map +1 -0
  119. package/types/components/BottomAppBar.d.ts +73 -0
  120. package/types/components/BottomAppBar.d.ts.map +1 -0
  121. package/types/components/BottomSheet.d.ts +109 -0
  122. package/types/components/BottomSheet.d.ts.map +1 -0
  123. package/types/components/Box.d.ts +16 -0
  124. package/types/components/Box.d.ts.map +1 -0
  125. package/types/components/Button.d.ts +714 -0
  126. package/types/components/Button.d.ts.map +1 -0
  127. package/types/components/Card.d.ts +412 -0
  128. package/types/components/Card.d.ts.map +1 -0
  129. package/types/components/Checkbox.d.ts +205 -0
  130. package/types/components/Checkbox.d.ts.map +1 -0
  131. package/types/components/CheckboxIcon.d.ts +44 -0
  132. package/types/components/CheckboxIcon.d.ts.map +1 -0
  133. package/types/components/Chip.d.ts +1425 -0
  134. package/types/components/Chip.d.ts.map +1 -0
  135. package/types/components/Dialog.d.ts +286 -0
  136. package/types/components/Dialog.d.ts.map +1 -0
  137. package/types/components/DialogActions.d.ts +4 -0
  138. package/types/components/DialogActions.d.ts.map +1 -0
  139. package/types/components/Display.d.ts +45 -0
  140. package/types/components/Display.d.ts.map +1 -0
  141. package/types/components/Divider.d.ts +10 -0
  142. package/types/components/Divider.d.ts.map +1 -0
  143. package/types/components/Fab.d.ts +741 -0
  144. package/types/components/Fab.d.ts.map +1 -0
  145. package/types/components/FabContainer.d.ts +10 -0
  146. package/types/components/FabContainer.d.ts.map +1 -0
  147. package/types/components/FilterChip.d.ts +4283 -0
  148. package/types/components/FilterChip.d.ts.map +1 -0
  149. package/types/components/Grid.d.ts +37 -0
  150. package/types/components/Grid.d.ts.map +1 -0
  151. package/types/components/Headline.d.ts +47 -0
  152. package/types/components/Headline.d.ts.map +1 -0
  153. package/types/components/Icon.d.ts +103 -0
  154. package/types/components/Icon.d.ts.map +1 -0
  155. package/types/components/IconButton.d.ts +1486 -0
  156. package/types/components/IconButton.d.ts.map +1 -0
  157. package/types/components/Input.d.ts +51288 -0
  158. package/types/components/Input.d.ts.map +1 -0
  159. package/types/components/InputChip.d.ts +243 -0
  160. package/types/components/InputChip.d.ts.map +1 -0
  161. package/types/components/Label.d.ts +29 -0
  162. package/types/components/Label.d.ts.map +1 -0
  163. package/types/components/List.d.ts +31 -0
  164. package/types/components/List.d.ts.map +1 -0
  165. package/types/components/ListItem.d.ts +349 -0
  166. package/types/components/ListItem.d.ts.map +1 -0
  167. package/types/components/ListOption.d.ts +1493 -0
  168. package/types/components/ListOption.d.ts.map +1 -0
  169. package/types/components/Listbox.d.ts +12012 -0
  170. package/types/components/Listbox.d.ts.map +1 -0
  171. package/types/components/Menu.d.ts +119 -0
  172. package/types/components/Menu.d.ts.map +1 -0
  173. package/types/components/MenuItem.d.ts +3109 -0
  174. package/types/components/MenuItem.d.ts.map +1 -0
  175. package/types/components/NavBar.d.ts +18 -0
  176. package/types/components/NavBar.d.ts.map +1 -0
  177. package/types/components/NavBarItem.d.ts +186 -0
  178. package/types/components/NavBarItem.d.ts.map +1 -0
  179. package/types/components/NavDrawer.d.ts +108 -0
  180. package/types/components/NavDrawer.d.ts.map +1 -0
  181. package/types/components/NavDrawerItem.d.ts +186 -0
  182. package/types/components/NavDrawerItem.d.ts.map +1 -0
  183. package/types/components/NavItem.d.ts +190 -0
  184. package/types/components/NavItem.d.ts.map +1 -0
  185. package/types/components/NavRail.d.ts +109 -0
  186. package/types/components/NavRail.d.ts.map +1 -0
  187. package/types/components/NavRailItem.d.ts +186 -0
  188. package/types/components/NavRailItem.d.ts.map +1 -0
  189. package/types/components/Page.d.ts +24 -0
  190. package/types/components/Page.d.ts.map +1 -0
  191. package/types/components/Pane.d.ts +44 -0
  192. package/types/components/Pane.d.ts.map +1 -0
  193. package/types/components/Popup.d.ts +76 -0
  194. package/types/components/Popup.d.ts.map +1 -0
  195. package/types/components/Progress.d.ts +19 -0
  196. package/types/components/Progress.d.ts.map +1 -0
  197. package/types/components/Radio.d.ts +199 -0
  198. package/types/components/Radio.d.ts.map +1 -0
  199. package/types/components/RadioIcon.d.ts +46 -0
  200. package/types/components/RadioIcon.d.ts.map +1 -0
  201. package/types/components/Ripple.d.ts +34 -0
  202. package/types/components/Ripple.d.ts.map +1 -0
  203. package/types/components/Root.d.ts +68 -0
  204. package/types/components/Root.d.ts.map +1 -0
  205. package/types/components/Scrim.d.ts +6 -0
  206. package/types/components/Scrim.d.ts.map +1 -0
  207. package/types/components/Search.d.ts +16 -0
  208. package/types/components/Search.d.ts.map +1 -0
  209. package/types/components/SegmentedButton.d.ts +718 -0
  210. package/types/components/SegmentedButton.d.ts.map +1 -0
  211. package/types/components/SegmentedButtonGroup.d.ts +44 -0
  212. package/types/components/SegmentedButtonGroup.d.ts.map +1 -0
  213. package/types/components/Select.d.ts +1361 -0
  214. package/types/components/Select.d.ts.map +1 -0
  215. package/types/components/Shape.d.ts +10 -0
  216. package/types/components/Shape.d.ts.map +1 -0
  217. package/types/components/SideSheet.d.ts +106 -0
  218. package/types/components/SideSheet.d.ts.map +1 -0
  219. package/types/components/Slider.d.ts +382 -0
  220. package/types/components/Slider.d.ts.map +1 -0
  221. package/types/components/Snackbar.d.ts +65 -0
  222. package/types/components/Snackbar.d.ts.map +1 -0
  223. package/types/components/SnackbarContainer.d.ts +6 -0
  224. package/types/components/SnackbarContainer.d.ts.map +1 -0
  225. package/types/components/Surface.d.ts +45 -0
  226. package/types/components/Surface.d.ts.map +1 -0
  227. package/types/components/Switch.d.ts +183 -0
  228. package/types/components/Switch.d.ts.map +1 -0
  229. package/types/components/SwitchIcon.d.ts +169 -0
  230. package/types/components/SwitchIcon.d.ts.map +1 -0
  231. package/types/components/Tab.d.ts +879 -0
  232. package/types/components/Tab.d.ts.map +1 -0
  233. package/types/components/TabContent.d.ts +122 -0
  234. package/types/components/TabContent.d.ts.map +1 -0
  235. package/types/components/TabList.d.ts +6266 -0
  236. package/types/components/TabList.d.ts.map +1 -0
  237. package/types/components/TabPanel.d.ts +28 -0
  238. package/types/components/TabPanel.d.ts.map +1 -0
  239. package/types/components/Table.d.ts +2 -0
  240. package/types/components/Table.d.ts.map +1 -0
  241. package/types/components/TextArea.d.ts +1394 -0
  242. package/types/components/TextArea.d.ts.map +1 -0
  243. package/types/components/Title.d.ts +47 -0
  244. package/types/components/Title.d.ts.map +1 -0
  245. package/types/components/Tooltip.d.ts +49 -0
  246. package/types/components/Tooltip.d.ts.map +1 -0
  247. package/types/components/TopAppBar.d.ts +130 -0
  248. package/types/components/TopAppBar.d.ts.map +1 -0
  249. package/types/constants/colorKeywords.d.ts +2 -0
  250. package/types/constants/colorKeywords.d.ts.map +1 -0
  251. package/types/constants/shapes.d.ts +38 -0
  252. package/types/constants/shapes.d.ts.map +1 -0
  253. package/types/constants/typography.d.ts +212 -0
  254. package/types/constants/typography.d.ts.map +1 -0
  255. package/types/core/Composition.d.ts +252 -0
  256. package/types/core/Composition.d.ts.map +1 -0
  257. package/types/core/CompositionAdapter.d.ts +92 -0
  258. package/types/core/CompositionAdapter.d.ts.map +1 -0
  259. package/types/core/CustomElement.d.ts +302 -0
  260. package/types/core/CustomElement.d.ts.map +1 -0
  261. package/types/core/css.d.ts +44 -0
  262. package/types/core/css.d.ts.map +1 -0
  263. package/types/core/customTypes.d.ts +26 -0
  264. package/types/core/customTypes.d.ts.map +1 -0
  265. package/types/core/dom.d.ts +32 -0
  266. package/types/core/dom.d.ts.map +1 -0
  267. package/types/core/jsonMergePatch.d.ts +31 -0
  268. package/types/core/jsonMergePatch.d.ts.map +1 -0
  269. package/types/core/observe.d.ts +113 -0
  270. package/types/core/observe.d.ts.map +1 -0
  271. package/types/core/optimizations.d.ts +7 -0
  272. package/types/core/optimizations.d.ts.map +1 -0
  273. package/types/core/template.d.ts +47 -0
  274. package/types/core/template.d.ts.map +1 -0
  275. package/types/core/uid.d.ts +6 -0
  276. package/types/core/uid.d.ts.map +1 -0
  277. package/types/dom/HTMLOptionsCollectionProxy.d.ts +18 -0
  278. package/types/dom/HTMLOptionsCollectionProxy.d.ts.map +1 -0
  279. package/types/index.d.ts +88 -0
  280. package/types/index.d.ts.map +1 -0
  281. package/types/loaders/palette.d.ts +2 -0
  282. package/types/loaders/palette.d.ts.map +1 -0
  283. package/types/loaders/theme.d.ts +2 -0
  284. package/types/loaders/theme.d.ts.map +1 -0
  285. package/types/mixins/AriaReflectorMixin.d.ts +23 -0
  286. package/types/mixins/AriaReflectorMixin.d.ts.map +1 -0
  287. package/types/mixins/AriaToolbarMixin.d.ts +32 -0
  288. package/types/mixins/AriaToolbarMixin.d.ts.map +1 -0
  289. package/types/mixins/ControlMixin.d.ts +124 -0
  290. package/types/mixins/ControlMixin.d.ts.map +1 -0
  291. package/types/mixins/DelegatesFocusMixin.d.ts +5 -0
  292. package/types/mixins/DelegatesFocusMixin.d.ts.map +1 -0
  293. package/types/mixins/DensityMixin.d.ts +5 -0
  294. package/types/mixins/DensityMixin.d.ts.map +1 -0
  295. package/types/mixins/ElevationMixin.d.ts +33 -0
  296. package/types/mixins/ElevationMixin.d.ts.map +1 -0
  297. package/types/mixins/FlexableMixin.d.ts +13 -0
  298. package/types/mixins/FlexableMixin.d.ts.map +1 -0
  299. package/types/mixins/FormAssociatedMixin.d.ts +122 -0
  300. package/types/mixins/FormAssociatedMixin.d.ts.map +1 -0
  301. package/types/mixins/HyperlinkMixin.d.ts +22 -0
  302. package/types/mixins/HyperlinkMixin.d.ts.map +1 -0
  303. package/types/mixins/InputMixin.d.ts +179 -0
  304. package/types/mixins/InputMixin.d.ts.map +1 -0
  305. package/types/mixins/KeyboardNavMixin.d.ts +47 -0
  306. package/types/mixins/KeyboardNavMixin.d.ts.map +1 -0
  307. package/types/mixins/NavigationListenerMixin.d.ts +8 -0
  308. package/types/mixins/NavigationListenerMixin.d.ts.map +1 -0
  309. package/types/mixins/PopupMixin.d.ts +82 -0
  310. package/types/mixins/PopupMixin.d.ts.map +1 -0
  311. package/types/mixins/RTLObserverMixin.d.ts +7 -0
  312. package/types/mixins/RTLObserverMixin.d.ts.map +1 -0
  313. package/types/mixins/ResizeObserverMixin.d.ts +12 -0
  314. package/types/mixins/ResizeObserverMixin.d.ts.map +1 -0
  315. package/types/mixins/RippleMixin.d.ts +92 -0
  316. package/types/mixins/RippleMixin.d.ts.map +1 -0
  317. package/types/mixins/ScrollListenerMixin.d.ts +41 -0
  318. package/types/mixins/ScrollListenerMixin.d.ts.map +1 -0
  319. package/types/mixins/SemiStickyMixin.d.ts +50 -0
  320. package/types/mixins/SemiStickyMixin.d.ts.map +1 -0
  321. package/types/mixins/ShapeMaskedMixin.d.ts +9 -0
  322. package/types/mixins/ShapeMaskedMixin.d.ts.map +1 -0
  323. package/types/mixins/ShapeMixin.d.ts +38 -0
  324. package/types/mixins/ShapeMixin.d.ts.map +1 -0
  325. package/types/mixins/StateMixin.d.ts +27 -0
  326. package/types/mixins/StateMixin.d.ts.map +1 -0
  327. package/types/mixins/TextFieldMixin.d.ts +1354 -0
  328. package/types/mixins/TextFieldMixin.d.ts.map +1 -0
  329. package/types/mixins/ThemableMixin.d.ts +9 -0
  330. package/types/mixins/ThemableMixin.d.ts.map +1 -0
  331. package/types/mixins/TooltipTriggerMixin.d.ts +106 -0
  332. package/types/mixins/TooltipTriggerMixin.d.ts.map +1 -0
  333. package/types/mixins/TouchTargetMixin.d.ts +3 -0
  334. package/types/mixins/TouchTargetMixin.d.ts.map +1 -0
  335. package/types/mixins/TypographyMixin.d.ts +17 -0
  336. package/types/mixins/TypographyMixin.d.ts.map +1 -0
  337. package/types/services/rtl.d.ts +3 -0
  338. package/types/services/rtl.d.ts.map +1 -0
  339. package/types/services/svgAlias.d.ts +13 -0
  340. package/types/services/svgAlias.d.ts.map +1 -0
  341. package/types/services/theme.d.ts +45 -0
  342. package/types/services/theme.d.ts.map +1 -0
  343. package/types/utils/cli.d.ts +3 -0
  344. package/types/utils/cli.d.ts.map +1 -0
  345. package/types/utils/function.d.ts +3 -0
  346. package/types/utils/function.d.ts.map +1 -0
  347. package/types/utils/jsx-runtime.d.ts +20 -0
  348. package/types/utils/jsx-runtime.d.ts.map +1 -0
  349. package/types/utils/material-color/blend.d.ts +34 -0
  350. package/types/utils/material-color/blend.d.ts.map +1 -0
  351. package/types/utils/material-color/hct/Cam16.d.ts +142 -0
  352. package/types/utils/material-color/hct/Cam16.d.ts.map +1 -0
  353. package/types/utils/material-color/hct/Hct.d.ts +93 -0
  354. package/types/utils/material-color/hct/Hct.d.ts.map +1 -0
  355. package/types/utils/material-color/hct/ViewingConditions.d.ts +69 -0
  356. package/types/utils/material-color/hct/ViewingConditions.d.ts.map +1 -0
  357. package/types/utils/material-color/hct/hctSolver.d.ts +30 -0
  358. package/types/utils/material-color/hct/hctSolver.d.ts.map +1 -0
  359. package/types/utils/material-color/helper.d.ts +8 -0
  360. package/types/utils/material-color/helper.d.ts.map +1 -0
  361. package/types/utils/material-color/palettes/CorePalette.d.ts +75 -0
  362. package/types/utils/material-color/palettes/CorePalette.d.ts.map +1 -0
  363. package/types/utils/material-color/palettes/TonalPalette.d.ts +38 -0
  364. package/types/utils/material-color/palettes/TonalPalette.d.ts.map +1 -0
  365. package/types/utils/material-color/scheme/Scheme.d.ts +264 -0
  366. package/types/utils/material-color/scheme/Scheme.d.ts.map +1 -0
  367. package/types/utils/material-color/utils/color.d.ts +172 -0
  368. package/types/utils/material-color/utils/color.d.ts.map +1 -0
  369. package/types/utils/material-color/utils/math.d.ts +94 -0
  370. package/types/utils/material-color/utils/math.d.ts.map +1 -0
  371. package/types/utils/pixelmatch.d.ts +22 -0
  372. package/types/utils/pixelmatch.d.ts.map +1 -0
  373. package/types/utils/popup.d.ts +106 -0
  374. package/types/utils/popup.d.ts.map +1 -0
  375. package/types/utils/searchParams.d.ts +3 -0
  376. package/types/utils/searchParams.d.ts.map +1 -0
  377. package/types/utils/svg.d.ts +7 -0
  378. package/types/utils/svg.d.ts.map +1 -0
  379. package/utils/material-color/scheme/Scheme.js +1 -1
  380. package/utils/pixelmatch.js +360 -0
  381. package/utils/popup.js +86 -10
  382. package/utils/searchParams.js +19 -0
  383. package/components/ExtendedFab.js +0 -32
  384. package/components/Layout.js +0 -504
  385. package/components/Nav.js +0 -38
  386. package/core/DomAdapter.js +0 -586
  387. package/core/ICustomElement.d.ts +0 -291
  388. package/core/ICustomElement.js +0 -1
  389. package/core/test.js +0 -126
  390. package/core/typings.d.ts +0 -142
  391. package/core/typings.js +0 -1
  392. package/mixins/SurfaceMixin.js +0 -127
  393. package/theming/loader.js +0 -22
  394. /package/{utils/color_keywords.js → constants/colorKeywords.js} +0 -0
@@ -1,11 +1,117 @@
1
1
  /* eslint-disable max-classes-per-file */
2
2
 
3
3
  import Composition from './Composition.js';
4
- import { ICustomElement } from './ICustomElement.js';
4
+ import { css } from './css.js';
5
5
  import { attrNameFromPropName, attrValueFromDataValue } from './dom.js';
6
6
  import { applyMergePatch } from './jsonMergePatch.js';
7
7
  import { defineObservableProperty } from './observe.js';
8
- import { addInlineFunction, css, html } from './template.js';
8
+ import { addInlineFunction, html } from './template.js';
9
+
10
+ /** @typedef {import('./observe.js').ObserverPropertyType} ObserverPropertyType */
11
+
12
+ /**
13
+ * @template {any} T
14
+ * @typedef {{
15
+ * [P in keyof T]:
16
+ * T[P] extends (...args:any[]) => infer T2 ? T2
17
+ * : T[P] extends ObserverPropertyType
18
+ * ? import('./observe.js').ParsedObserverPropertyType<T[P]>
19
+ * : T[P] extends {type: ObserverPropertyType}
20
+ * ? import('./observe.js').ParsedObserverPropertyType<T[P]['type']>
21
+ * : T[P] extends ObserverOptions<null, infer T2>
22
+ * ? unknown extends T2 ? string : T2
23
+ * : never
24
+ * }} ParsedProps
25
+ */
26
+
27
+ /**
28
+ * @template {ObserverPropertyType} T1
29
+ * @template {any} T2
30
+ * @template {Object} [C=any]
31
+ * @typedef {import('./observe.js').ObserverOptions<T1,T2,C>} ObserverOptions
32
+ */
33
+
34
+ /**
35
+ * @template {{ prototype: unknown; }} T
36
+ * @typedef {T} ClassOf<T>
37
+ */
38
+
39
+ /**
40
+ * @template {any} [T=any]
41
+ * @template {any[]} [A=any[]]
42
+ * @typedef {abstract new (...args: A) => T} Class
43
+ */
44
+
45
+ /**
46
+ * @template {any} T1
47
+ * @template {any} [T2=T1]
48
+ * @callback HTMLTemplater
49
+ * @param {TemplateStringsArray} string
50
+ * @param {...(string|DocumentFragment|Element|((this:T1, data:T2) => any))} substitutions
51
+ * @return {DocumentFragment}
52
+ */
53
+
54
+ /**
55
+ * @template {any} [T1=any]
56
+ * @template {any} [T2=T1]
57
+ * @typedef {Object} CallbackArguments
58
+ * @prop {Composition<T1>} composition
59
+ * @prop {Record<string, HTMLElement>} refs
60
+ * @prop {HTMLTemplater<T1, Partial<T2>>} html
61
+ * @prop {(fn: (this:T1, data: T2) => any) => string} inline
62
+ * @prop {DocumentFragment} template
63
+ * @prop {T1} element
64
+ */
65
+
66
+ /**
67
+ * @template {any} T1
68
+ * @template {any} [T2=T1]
69
+ * @typedef {{
70
+ * composed?: (this: T1, options: CallbackArguments<T1, T2>) => any,
71
+ * constructed?: (this: T1, options: CallbackArguments<T1, T2>) => any,
72
+ * connected?: (this: T1, options: CallbackArguments<T1, T2>) => any,
73
+ * disconnected?: (this: T1, options: CallbackArguments<T1, T2>) => any,
74
+ * props?: {
75
+ * [P in keyof T1] : (
76
+ * this: T1,
77
+ * oldValue: T1[P],
78
+ * newValue: T1[P],
79
+ * changes:any,
80
+ * element: T1
81
+ * ) => any
82
+ * },
83
+ * attrs?: {[K in keyof any]: (
84
+ * this: T1,
85
+ * oldValue: string,
86
+ * newValue: string,
87
+ * element: T1
88
+ * ) => unknown
89
+ * },
90
+ * } & {
91
+ * [P in keyof T1 & string as `${P}Changed`]?: (
92
+ * this: T1,
93
+ * oldValue: T1[P],
94
+ * newValue: T1[P],
95
+ * changes:any,
96
+ * element: T1
97
+ * ) => any
98
+ * }} CompositionCallback
99
+ */
100
+
101
+ /**
102
+ * @template {Object} C
103
+ * @typedef {{
104
+ * [P in string] :
105
+ * ObserverPropertyType
106
+ * | ObserverOptions<ObserverPropertyType, unknown, C>
107
+ * | ((this:C, data:Partial<C>, fn?: () => any) => any)
108
+ * }} IDLParameter
109
+ */
110
+
111
+ /**
112
+ * @template T
113
+ * @typedef {(T | Array<[keyof T & string, T[keyof T]]>)} ObjectOrObjectEntries
114
+ */
9
115
 
10
116
  /**
11
117
  * @template {abstract new (...args: any) => unknown} T
@@ -33,57 +139,49 @@ export function cloneAttributeCallback(name, target) {
33
139
  };
34
140
  }
35
141
 
36
- const EVENT_PREFIX_REGEX = /^([*1~]+)?(.*)$/;
37
-
38
142
  /**
39
143
  * Web Component that can cache templates for minification or performance
40
144
  */
41
- export default class CustomElement extends ICustomElement {
145
+ export default class CustomElement extends HTMLElement {
42
146
  /** @type {string} */
43
147
  static elementName;
44
148
 
45
149
  /** @return {Iterable<string>} */
46
150
  static get observedAttributes() {
47
- const s = new Set();
48
- for (const config of this.propList.values()) {
49
- if (config.reflect === true || config.reflect === 'read') {
50
- s.add(config.attr);
51
- }
52
- }
53
- return s;
151
+ return this.attrList.keys();
54
152
  }
55
153
 
56
154
  /** @type {import('./Composition.js').Compositor<?>} */
57
155
  compose() {
58
- if (this.#composition) {
59
- console.warn('Already composed. Generating *new* composition...');
60
- }
61
- this.#composition = new Composition();
62
- return this.#composition;
156
+ // eslint-disable-next-line no-return-assign
157
+ return (this.#composition ??= new Composition());
63
158
  }
64
159
 
65
160
  /** @type {Composition<?>} */
66
161
  static _composition = null;
67
162
 
68
- /** @type {Map<string, import('./typings.js').ObserverConfiguration<?,?,?>>} */
163
+ /** @type {Map<string, import('./observe.js').ObserverConfiguration<?,?,?>>} */
69
164
  static _props = new Map();
70
165
 
166
+ /** @type {Map<string, import('./observe.js').ObserverConfiguration<?,?,?>>} */
167
+ static _attrs = new Map();
168
+
71
169
  /** @type {Map<string, Function[]>} */
72
170
  static _propChangedCallbacks = new Map();
73
171
 
74
172
  /** @type {Map<string, Function[]>} */
75
173
  static _attributeChangedCallbacks = new Map();
76
174
 
77
- /** @type {typeof ICustomElement._onComposeCallbacks} */
175
+ /** @type {((callback: CallbackArguments) => any)[]} */
78
176
  static _onComposeCallbacks = [];
79
177
 
80
- /** @type {typeof ICustomElement._onConnectedCallbacks} */
178
+ /** @type {((callback: CallbackArguments) => any)[]} */
81
179
  static _onConnectedCallbacks = [];
82
180
 
83
- /** @type {typeof ICustomElement._onDisconnectedCallbacks} */
181
+ /** @type {((callback: CallbackArguments) => any)[]} */
84
182
  static _onDisconnectedCallbacks = [];
85
183
 
86
- /** @type {typeof ICustomElement._onConstructedCallbacks} */
184
+ /** @type {((callback: CallbackArguments) => any)[]} */
87
185
  static _onConstructedCallbacks = [];
88
186
 
89
187
  static interpolatesTemplate = true;
@@ -103,68 +201,189 @@ export default class CustomElement extends ICustomElement {
103
201
  /** @type {Map<string, typeof CustomElement>} */
104
202
  static registrations = new Map();
105
203
 
106
- /** @type {typeof ICustomElement.expressions} */
107
- static expressions = this.set;
204
+ /**
205
+ * Expressions are idempotent functions that are selectively called whenever
206
+ * a render is requested.
207
+ * Expressions are constructed exactly as methods though differ in expected
208
+ * arguments. The first argument should be destructured to ensure each used
209
+ * property is accessed at least once in order to inspect used properties.
210
+ *
211
+ * The Composition API will inspect this function with a proxy for `this` to
212
+ * catalog what observables are used by the expression. This allows the
213
+ * Composition API to build a cache as well as selective invoke the expression
214
+ * only when needed.
215
+ *
216
+ * When used with in element templates, the element itself will be passed as
217
+ * its first argument.
218
+ * ````js
219
+ * Button
220
+ * .prop('filled', 'boolean')
221
+ * .prop('outlined', 'boolean')
222
+ * .expresssions({
223
+ * _isFilledOrOutlined({filled, outlined}) {
224
+ * return (filled || outlined)
225
+ * },
226
+ * })
227
+ * .html`<div custom={_isFilledOrOutlined}></div>`;
228
+ * ````
229
+ *
230
+ * When used with external data source, that data source
231
+ * will be passed to the expression with all properties being `null` at first
232
+ * inspection.
233
+ * ````js
234
+ * const externalData = {first: 'John', last: 'Doe'};
235
+ * ContactCard
236
+ * .expresssions({
237
+ * _fullName({first, last}) {
238
+ * return [first, last].filter(Boolean).join(' ');
239
+ * },
240
+ * })
241
+ * myButton.render(externalData);
242
+ * ````
243
+ *
244
+ * Expressions may be support argumentless calls by using default
245
+ * parameters with `this`.
246
+ * ````js
247
+ * Button
248
+ * .expresssions({
249
+ * isFilledOrOutlined({filled, outlined} = this) {
250
+ * return (filled || outlined)
251
+ * },
252
+ * });
253
+ * myButton.isFilledorOutlined();
254
+ * ````
255
+ * @type {{
256
+ * <
257
+ * CLASS extends typeof CustomElement,
258
+ * ARGS extends ConstructorParameters<CLASS>,
259
+ * INSTANCE extends InstanceType<CLASS>,
260
+ * PROPS extends {
261
+ * [K in keyof any]: K extends `_${any}` ? ((data: INSTANCE, state?: Record<string, any>) => string|boolean|null)
262
+ * : ((data?: INSTANCE, state?: Record<string, any>) => string|boolean|null)
263
+ * } & ThisType<INSTANCE>
264
+ * >(this: CLASS, expressions: PROPS & ThisType<INSTANCE & PROPS>):
265
+ * CLASS & Class<{
266
+ * [K in keyof PROPS]: K extends `_${any}` ? never : () => ReturnType<PROPS[K]> }
267
+ * ,ARGS>
268
+ * }}
269
+ */
270
+ static expressions = /** @type {any} */ (this.set);
108
271
 
109
- /** @type {typeof ICustomElement.methods} */
110
272
  static methods = this.set;
111
273
 
112
- /** @type {typeof ICustomElement.overrides} */
113
- static overrides = this.set;
274
+ /**
275
+ * @type {{
276
+ * <
277
+ * CLASS extends typeof CustomElement,
278
+ * ARGS extends ConstructorParameters<CLASS>,
279
+ * INSTANCE extends InstanceType<CLASS>,
280
+ * PROPS extends Partial<INSTANCE>>
281
+ * (this: CLASS, source: PROPS & ThisType<PROPS & INSTANCE>, options?: Partial<PropertyDescriptor>)
282
+ * : CLASS & Class<PROPS,ARGS>
283
+ * }}
284
+ */
285
+ static overrides = /** @type {any} */ (this.set);
286
+
287
+ /**
288
+ * @type {{
289
+ * <
290
+ * CLASS extends typeof CustomElement,
291
+ * ARGS extends ConstructorParameters<CLASS>,
292
+ * INSTANCE extends InstanceType<CLASS>,
293
+ * KEY extends string,
294
+ * OPTIONS extends ObserverPropertyType
295
+ * | ObserverOptions<ObserverPropertyType, unknown, INSTANCE>
296
+ * | ((this:INSTANCE, data:Partial<INSTANCE>, fn?: () => any) => any),
297
+ * VALUE extends Record<KEY, OPTIONS extends (...args2:any[]) => infer R ? R
298
+ * : OPTIONS extends ObserverPropertyType ? import('./observe.js').ParsedObserverPropertyType<OPTIONS>
299
+ * : OPTIONS extends {type: 'object'} & ObserverOptions<any, infer R> ? (unknown extends R ? object : R)
300
+ * : OPTIONS extends {type: ObserverPropertyType} ? import('./observe.js').ParsedObserverPropertyType<OPTIONS['type']>
301
+ * : OPTIONS extends ObserverOptions<any, infer R> ? (unknown extends R ? string : R)
302
+ * : never
303
+ * >
304
+ * > (this: CLASS, name: KEY, options: OPTIONS)
305
+ * : CLASS & Class<VALUE,ARGS>;
306
+ * }}
307
+ */
308
+ static props = /** @type {any} */ (this.observe);
114
309
 
115
- /** @type {typeof ICustomElement.props} */
116
- static props = this.observe;
310
+ static idl = this.prop;
117
311
 
118
312
  /**
119
- * @template {typeof CustomElement} T
120
313
  * @this T
314
+ * @template {typeof CustomElement} T
121
315
  * @template {keyof T} K
122
316
  * @param {K} collection
123
317
  * @param {T[K] extends (infer R)[] ? R : never} callback
124
318
  */
125
319
  static _addCallback(collection, callback) {
126
320
  if (!this.hasOwnProperty(collection)) {
127
- this[collection] = [
128
- ...this[collection],
129
- ];
321
+ // @ts-expect-error not typed
322
+ this[collection] = [...this[collection], callback];
323
+ return;
130
324
  }
325
+ // @ts-expect-error any
131
326
  this[collection].push(callback);
132
327
  }
133
328
 
134
329
  /**
135
330
  * Append parts to composition
136
- * @type {typeof ICustomElement.append}
331
+ * @type {{
332
+ * <
333
+ * T extends typeof CustomElement,
334
+ * >
335
+ * (this: T, ...parts: ConstructorParameters<typeof Composition<InstanceType<T>>>): T;
336
+ * }}
137
337
  */
138
338
  static append(...parts) {
139
- this.on({
140
- composed({ composition }) {
141
- // console.debug('onComposed:append', ...parts);
142
- composition.append(...parts);
143
- },
339
+ this._addCallback('_onComposeCallbacks', ({ composition }) => {
340
+ composition.append(...parts);
144
341
  });
145
342
  // @ts-expect-error Can't cast T
146
343
  return this;
147
344
  }
148
345
 
149
346
  /**
150
- * Appends styles to composition
151
- * @type {typeof ICustomElement.css}
347
+ * After composition, invokes callback.
348
+ * May be called multiple times.
349
+ * @type {{
350
+ * <
351
+ * T1 extends typeof CustomElement,
352
+ * T2 extends InstanceType<T1>,
353
+ * T3 extends CompositionCallback<T2, T2>['composed'],
354
+ * >
355
+ * (this: T1, callback: T3): T1
356
+ * }}
152
357
  */
153
- static css(array, ...substitutions) {
154
- if (Array.isArray(array)) {
155
- // @ts-expect-error Complex cast
156
- this.append(css(array, ...substitutions));
157
- } else {
158
- // @ts-expect-error Complex cast
159
- this.append(array, ...substitutions);
160
- }
358
+ static recompose(callback) {
359
+ this._addCallback('_onComposeCallbacks', callback);
161
360
  // @ts-expect-error Can't cast T
162
361
  return this;
163
362
  }
164
363
 
165
- /** @type {typeof ICustomElement['setSchema']} */
166
- static setSchema(schema) {
167
- this.schema = schema;
364
+ /**
365
+ * Appends styles to composition
366
+ * @type {{
367
+ * <
368
+ * T1 extends typeof CustomElement,
369
+ * T2 extends TemplateStringsArray|HTMLStyleElement|CSSStyleSheet|string>(
370
+ * this: T1,
371
+ * array: T2,
372
+ * ...rest: T2 extends string ? any : T2 extends TemplateStringsArray ? any[] : (HTMLStyleElement|CSSStyleSheet)[]
373
+ * ): T1
374
+ * }}
375
+ */
376
+ static css(array, ...substitutions) {
377
+ this._addCallback('_onComposeCallbacks', ({ composition }) => {
378
+ if (typeof array === 'string' || Array.isArray(array)) {
379
+ // @ts-expect-error Complex cast
380
+ composition.append(css(array, ...substitutions));
381
+ } else {
382
+ // @ts-expect-error Complex cast
383
+ composition.append(array, ...substitutions);
384
+ }
385
+ });
386
+
168
387
  // @ts-expect-error Can't cast T
169
388
  return this;
170
389
  }
@@ -173,7 +392,9 @@ export default class CustomElement extends ICustomElement {
173
392
  * Registers class asynchronously at end of current event loop cycle
174
393
  * via `queueMicrotask`. If class is registered before then,
175
394
  * does nothing.
176
- * @type {typeof ICustomElement['autoRegister']}
395
+ * @type {{
396
+ * <T extends typeof CustomElement>(this: T, elementName: string): T;
397
+ * }}
177
398
  */
178
399
  static autoRegister(elementName) {
179
400
  if (this.hasOwnProperty('defined') && this.defined) {
@@ -188,14 +409,18 @@ export default class CustomElement extends ICustomElement {
188
409
 
189
410
  /**
190
411
  * Appends DocumentFragment to composition
191
- * @type {typeof ICustomElement.html}
412
+ * @type {{
413
+ * <T extends typeof CustomElement>(
414
+ * this: T,
415
+ * string: TemplateStringsArray,
416
+ * ...substitutions: (string|Element|((this:InstanceType<T>, data:InstanceType<T>, injections?:any) => any))[]
417
+ * ): T
418
+ * }}
192
419
  */
193
420
  static html(strings, ...substitutions) {
194
- this.on({
195
- composed({ composition }) {
421
+ this._addCallback('_onComposeCallbacks', ({ composition }) => {
196
422
  // console.log('onComposed:html', strings);
197
- composition.append(html(strings, ...substitutions));
198
- },
423
+ composition.append(html(strings, ...substitutions));
199
424
  });
200
425
  // @ts-expect-error Can't cast T
201
426
  return this;
@@ -204,26 +429,28 @@ export default class CustomElement extends ICustomElement {
204
429
  /**
205
430
  * Extends base class into a new class.
206
431
  * Use to avoid mutating base class.
207
- * TODO: Add constructor arguments typing
208
- * @type {typeof ICustomElement.extend}
209
- */
210
- static extend() {
211
- // @ts-expect-error Can't cast T
212
- return class extends this {};
213
- }
214
-
215
- /**
216
- * Fix for Typescript not parsing constructor params
217
- * @type {typeof ICustomElement.tsClassFix}
432
+ * @type {{
433
+ * <T1 extends typeof CustomElement, T2 extends T1, T3 extends (Base:T1) => T2>
434
+ * (this: T1,customExtender?: T3|null): T3 extends null ? T1 : T2;
435
+ * }}
218
436
  */
219
- static tsClassFix() {
437
+ static extend(customExtender) {
220
438
  // @ts-expect-error Can't cast T
221
- return this;
439
+ return customExtender ? customExtender(this) : class extends this {};
222
440
  }
223
441
 
224
442
  /**
225
443
  * Assigns static values to class
226
- * @type {typeof ICustomElement.setStatic}
444
+ * @type {{
445
+ * <
446
+ * T1 extends typeof CustomElement,
447
+ * T2 extends {
448
+ * [K in keyof any]: (
449
+ * ((this:T1, ...args:any[]) => any)
450
+ * |string|number|boolean|any[]|object)}
451
+ * >
452
+ * (this: T1, source: T2 & ThisType<T1 & T2>):T1 & T2;
453
+ * }}
227
454
  */
228
455
  static setStatic(source) {
229
456
  Object.assign(this, source);
@@ -233,7 +460,15 @@ export default class CustomElement extends ICustomElement {
233
460
 
234
461
  /**
235
462
  * Assigns values directly to all instances (via prototype)
236
- * @type {typeof ICustomElement.set}
463
+ * @type {{
464
+ * <
465
+ * CLASS extends typeof CustomElement,
466
+ * ARGS extends ConstructorParameters<CLASS>,
467
+ * INSTANCE extends InstanceType<CLASS>,
468
+ * PROPS extends object>
469
+ * (this: CLASS, source: PROPS & ThisType<PROPS & INSTANCE>, options?: Partial<PropertyDescriptor>)
470
+ * : CLASS & Class<PROPS,ARGS>
471
+ * }}
237
472
  */
238
473
  static readonly(source, options) {
239
474
  // @ts-expect-error Can't cast T
@@ -242,7 +477,15 @@ export default class CustomElement extends ICustomElement {
242
477
 
243
478
  /**
244
479
  * Assigns values directly to all instances (via prototype)
245
- * @type {typeof ICustomElement.set}
480
+ * @type {{
481
+ * <
482
+ * CLASS extends typeof CustomElement,
483
+ * ARGS extends ConstructorParameters<CLASS>,
484
+ * INSTANCE extends InstanceType<CLASS>,
485
+ * PROPS extends object>
486
+ * (this: CLASS, source: PROPS & ThisType<PROPS & INSTANCE>, options?: Partial<PropertyDescriptor>)
487
+ * : CLASS & Class<PROPS,ARGS>
488
+ * }}
246
489
  */
247
490
  static set(source, options) {
248
491
  Object.defineProperties(
@@ -281,7 +524,14 @@ export default class CustomElement extends ICustomElement {
281
524
 
282
525
  /**
283
526
  * Returns result of calling mixin with current class
284
- * @type {typeof ICustomElement.mixin}
527
+ * @type {{
528
+ * <
529
+ * BASE extends typeof CustomElement,
530
+ * FN extends (...args:any[]) => any,
531
+ * RETURN extends ReturnType<FN>,
532
+ * SUBCLASS extends ClassOf<RETURN>,
533
+ * (this: BASE, mixin: FN): SUBCLASS & BASE
534
+ * }}
285
535
  */
286
536
  static mixin(mixin) {
287
537
  return mixin(this);
@@ -289,7 +539,9 @@ export default class CustomElement extends ICustomElement {
289
539
 
290
540
  /**
291
541
  * Registers class with window.customElements synchronously
292
- * @type {typeof ICustomElement['register']}
542
+ * @type {{
543
+ * <T extends typeof CustomElement>(this: T, elementName?: string, force?: boolean): T;
544
+ * }}
293
545
  */
294
546
  static register(elementName) {
295
547
  if (elementName) {
@@ -310,6 +562,13 @@ export default class CustomElement extends ICustomElement {
310
562
  return this._props;
311
563
  }
312
564
 
565
+ static get attrList() {
566
+ if (!this.hasOwnProperty('_attrs')) {
567
+ this._attrs = new Map(this._attrs);
568
+ }
569
+ return this._attrs;
570
+ }
571
+
313
572
  static get propChangedCallbacks() {
314
573
  if (!this.hasOwnProperty('_propChangedCallbacks')) {
315
574
  // structuredClone()
@@ -335,55 +594,82 @@ export default class CustomElement extends ICustomElement {
335
594
 
336
595
  /**
337
596
  * Creates observable property on instances (via prototype)
338
- * @template {import('./typings.js').ObserverPropertyType} [T1=null]
339
- * @template {import('./typings.js').ObserverPropertyType} [T2=null]
340
- * @template {any} [T3=null]
341
- * @param {string} name
342
- * @param {T1|import('./typings.js').ObserverOptions<T2,T3>} [typeOrOptions='string']
343
- * @return {(
344
- * T3 extends null ?
345
- * T2 extends null ?
346
- * T1 extends null ?
347
- * string
348
- * : import('./typings.js').ParsedObserverPropertyType<T1>
349
- * : import('./typings.js').ParsedObserverPropertyType<T2>
350
- * : T3
351
- * )}
597
+ * @type {{
598
+ * <
599
+ * CLASS extends typeof CustomElement,
600
+ * ARGS extends ConstructorParameters<CLASS>,
601
+ * INSTANCE extends InstanceType<CLASS>,
602
+ * KEY extends string,
603
+ * OPTIONS extends ObserverPropertyType
604
+ * | ObserverOptions<ObserverPropertyType, unknown, INSTANCE>
605
+ * | ((this:INSTANCE, data:Partial<INSTANCE>, fn?: () => any) => any),
606
+ * VALUE extends Record<KEY, OPTIONS extends (...args2:any[]) => infer R ? R
607
+ * : OPTIONS extends ObserverPropertyType ? import('./observe').ParsedObserverPropertyType<OPTIONS>
608
+ * : OPTIONS extends {type: 'object'} & ObserverOptions<any, infer R> ? (unknown extends R ? object : R)
609
+ * : OPTIONS extends {type: ObserverPropertyType} ? import('./observe').ParsedObserverPropertyType<OPTIONS['type']>
610
+ * : OPTIONS extends ObserverOptions<any, infer R> ? (unknown extends R ? string : R)
611
+ * : never
612
+ * >
613
+ * > (this: CLASS, name: KEY, options: OPTIONS)
614
+ * : CLASS & Class<VALUE,ARGS>
615
+ * }}
352
616
  */
353
617
  static prop(name, typeOrOptions) {
354
618
  // TODO: Cache and save configuration for reuse (mixins)
355
- /** @type {import('./typings.js').ObserverOptions<?,?>} */
356
- const options = {
357
- ...((typeof typeOrOptions === 'string') ? { type: typeOrOptions } : typeOrOptions),
358
- };
359
-
360
- const customCallback = options.changedCallback;
619
+ const config = defineObservableProperty(
620
+ /** @type {any} */ (this.prototype),
621
+ name,
622
+ /** @type {any} */ (typeOrOptions),
623
+ );
361
624
 
362
- if (customCallback) {
363
- // Move callback to later in stack for attribute-based changes as well
364
- this.onPropChanged({ [name]: customCallback });
625
+ const { changedCallback, attr, reflect, watchers } = config;
626
+ if (changedCallback) {
627
+ watchers.push([name, changedCallback]);
365
628
  }
366
-
367
629
  // TODO: Inspect possible closure bloat
368
- options.changedCallback = function wrappedChangedCallback(oldValue, newValue, changes) {
630
+ config.changedCallback = function wrappedChangedCallback(oldValue, newValue, changes) {
369
631
  this._onObserverPropertyChanged.call(this, name, oldValue, newValue, changes);
370
632
  };
371
633
 
372
- const config = defineObservableProperty(this.prototype, name, options);
373
-
374
634
  this.propList.set(name, config);
375
- for (const [prop, callback] of config.watchers) {
376
- this.on(`${prop}Changed`, callback);
635
+
636
+ if (attr && (reflect === true || reflect === 'read')) {
637
+ this.attrList.set(attr, config);
377
638
  }
378
639
 
379
- return config.INIT_SYMBOL;
640
+ this.onPropChanged(watchers);
641
+
642
+ // @ts-expect-error Can't cast T
643
+ return this;
380
644
  }
381
645
 
382
646
  /**
383
647
  * Define properties on instances via Object.defineProperties().
384
648
  * Automatically sets property non-enumerable if name begins with `_`.
385
649
  * Functions will be remapped as getters
386
- * @type {typeof ICustomElement.define}
650
+ * @type {{
651
+ * <
652
+ * CLASS extends typeof CustomElement,
653
+ * ARGS extends ConstructorParameters<CLASS>,
654
+ * INSTANCE extends InstanceType<CLASS>,
655
+ * PROPS extends {
656
+ * [P in keyof any] :
657
+ * {
658
+ * enumerable?: boolean;
659
+ * configurable?: boolean;
660
+ * writable?: boolean;
661
+ * value?: any;
662
+ * get?: ((this: INSTANCE) => any);
663
+ * set?: (this: INSTANCE, value: any) => void;
664
+ * } | ((this: INSTANCE, ...args:any[]) => any)
665
+ * },
666
+ * VALUE extends {
667
+ * [KEY in keyof PROPS]: PROPS[KEY] extends (...args2:any[]) => infer R ? R
668
+ * : PROPS[KEY] extends TypedPropertyDescriptor<infer R> ? R : never
669
+ * }>
670
+ * (this: CLASS, props: PROPS & ThisType<PROPS & INSTANCE>): CLASS
671
+ * & Class<VALUE,ARGS>
672
+ * }}
387
673
  */
388
674
  static define(props) {
389
675
  Object.defineProperties(
@@ -415,43 +701,68 @@ export default class CustomElement extends ICustomElement {
415
701
 
416
702
  static undefine(name) {
417
703
  Reflect.deleteProperty(this.prototype, name);
418
- if (this.propList.has(name)) {
419
- const config = this.propList.get(name);
420
- if (config.watchers.length && this.propChangedCallbacks.has(name)) {
421
- const propWatchers = this.propChangedCallbacks.get(name);
422
- for (const watcher of config.watchers) {
423
- const index = propWatchers.indexOf(watcher);
424
- if (index !== -1) {
425
- console.warn('Unwatching', name);
426
- propWatchers.splice(index, 1);
427
- }
704
+ if (!this.propList.has(name)) return this;
705
+ const { watchers, attr, reflect } = this.propList.get(name);
706
+ if (watchers.length && this.propChangedCallbacks.has(name)) {
707
+ const propWatchers = this.propChangedCallbacks.get(name);
708
+ for (const watcher of watchers) {
709
+ const index = propWatchers.indexOf(watcher);
710
+ if (index !== -1) {
711
+ console.warn('Unwatching', name);
712
+ propWatchers.splice(index, 1);
428
713
  }
429
714
  }
430
715
  }
716
+ if (attr && (reflect === true || reflect === 'read')) {
717
+ this.attrList.delete(attr);
718
+ }
431
719
  this.propList.delete(name);
720
+
432
721
  return this;
433
722
  }
434
723
 
435
724
  /**
436
725
  * Creates observable properties on instances
437
- * @type {typeof ICustomElement.observe}
726
+ * @type {{
727
+ * <
728
+ * CLASS extends typeof CustomElement,
729
+ * ARGS extends ConstructorParameters<CLASS>,
730
+ * INSTANCE extends InstanceType<CLASS>,
731
+ * PROPS extends IDLParameter<INSTANCE & VALUE>,
732
+ * VALUE extends {
733
+ * [KEY in keyof PROPS]:
734
+ * PROPS[KEY] extends (...args2:any[]) => infer R ? R
735
+ * : PROPS[KEY] extends ObserverPropertyType ? import('./observe').ParsedObserverPropertyType<PROPS[KEY]>
736
+ * : PROPS[KEY] extends {type: 'object'} & ObserverOptions<any, infer R> ? (unknown extends R ? object : R)
737
+ * : PROPS[KEY] extends {type: ObserverPropertyType} ? import('./observe').ParsedObserverPropertyType<PROPS[KEY]['type']>
738
+ * : PROPS[KEY] extends ObserverOptions<any, infer R> ? (unknown extends R ? string : R)
739
+ * : never
740
+ * },
741
+ * > (this: CLASS, props: PROPS)
742
+ * : CLASS & Class<VALUE,ARGS>
743
+ * }}
438
744
  */
439
745
  static observe(props) {
440
746
  for (const [name, typeOrOptions] of Object.entries(props ?? {})) {
441
- if (typeof typeOrOptions === 'function') {
442
- this.prop(name, {
443
- reflect: false,
444
- get: typeOrOptions,
445
- });
446
- } else {
447
- this.prop(name, typeOrOptions);
448
- }
747
+ /** @type {any} */
748
+ const options = (typeof typeOrOptions === 'function')
749
+ ? { reflect: false, get: typeOrOptions }
750
+ : typeOrOptions;
751
+
752
+ this.prop(name, options);
449
753
  }
450
754
  // @ts-expect-error Can't cast T
451
755
  return this;
452
756
  }
453
757
 
454
- /** @type {typeof ICustomElement.defineStatic} */
758
+ /**
759
+ * @type {{
760
+ * <
761
+ * T1 extends typeof CustomElement,
762
+ * T2 extends IDLParameter<T1>>
763
+ * (this: T1, props: T2):T1 & ParsedProps<T2>
764
+ * }}
765
+ */
455
766
  static defineStatic(props) {
456
767
  for (const [name, typeOrOptions] of Object.entries(props ?? {})) {
457
768
  const options = (typeof typeOrOptions === 'function')
@@ -468,12 +779,21 @@ export default class CustomElement extends ICustomElement {
468
779
  return this;
469
780
  }
470
781
 
471
- /** @type {typeof ICustomElement.events} */
782
+ /**
783
+ * @type {{
784
+ * <T extends typeof CustomElement>
785
+ * (
786
+ * this: T,
787
+ * listeners?: import('./Composition').CompositionEventListenerObject<InstanceType<T>>,
788
+ * options?: Partial<import('./Composition').CompositionEventListener<InstanceType<T>>>,
789
+ * ): T;
790
+ * }}
791
+ */
472
792
  static events(listeners, options) {
473
793
  this.on({
474
794
  composed({ composition }) {
475
795
  for (const [key, listenerOptions] of Object.entries(listeners)) {
476
- const [, flags, type] = key.match(EVENT_PREFIX_REGEX);
796
+ const [, flags, type] = key.match(/^([*1~]+)?(.*)$/);
477
797
  // TODO: Make abstract
478
798
  let prop;
479
799
  /** @type {string[]} */
@@ -513,7 +833,18 @@ export default class CustomElement extends ICustomElement {
513
833
  return this;
514
834
  }
515
835
 
516
- /** @type {typeof ICustomElement.childEvents} */
836
+ /**
837
+ * @type {{
838
+ * <T extends typeof CustomElement>
839
+ * (
840
+ * this: T,
841
+ * listenerMap: {
842
+ * [P in keyof any]: import('./Composition').CompositionEventListenerObject<InstanceType<T>>
843
+ * },
844
+ * options?: Partial<import('./Composition').CompositionEventListener<InstanceType<T>>>,
845
+ * ): T;
846
+ * }}
847
+ */
517
848
  static childEvents(listenerMap, options) {
518
849
  for (const [tag, listeners] of Object.entries(listenerMap)) {
519
850
  // @ts-expect-error Can't cast T
@@ -527,7 +858,7 @@ export default class CustomElement extends ICustomElement {
527
858
  return this;
528
859
  }
529
860
 
530
- /** @type {typeof ICustomElement.events} */
861
+ /** @type {typeof CustomElement['events']} */
531
862
  static rootEvents(listeners, options) {
532
863
  // @ts-expect-error Can't cast T
533
864
  return this.events(listeners, {
@@ -536,7 +867,17 @@ export default class CustomElement extends ICustomElement {
536
867
  });
537
868
  }
538
869
 
539
- /** @type {typeof ICustomElement['on']} */
870
+ /**
871
+ * @type {{
872
+ * <
873
+ * T1 extends typeof CustomElement,
874
+ * T2 extends InstanceType<T1>,
875
+ * T3 extends CompositionCallback<T2, T2>,
876
+ * T4 extends keyof T3,
877
+ * >
878
+ * (this: T1, name: T3|T4, callbacks?: T3[T4] & ThisType<T2>): T1
879
+ * }}
880
+ */
540
881
  static on(nameOrCallbacks, callback) {
541
882
  const callbacks = typeof nameOrCallbacks === 'string'
542
883
  ? { [nameOrCallbacks]: callback }
@@ -570,13 +911,34 @@ export default class CustomElement extends ICustomElement {
570
911
  return this;
571
912
  }
572
913
 
573
- /** @type {typeof ICustomElement['onPropChanged']} */
914
+ /**
915
+ * @type {{
916
+ * <
917
+ * T1 extends typeof CustomElement,
918
+ * T2 extends InstanceType<T1>
919
+ * >
920
+ * (
921
+ * this: T1,
922
+ * options: ObjectOrObjectEntries<{
923
+ * [P in keyof T2]? : (
924
+ * this: T2,
925
+ * oldValue: T2[P],
926
+ * newValue: T2[P],
927
+ * changes:any,
928
+ * element: T2
929
+ * ) => void
930
+ * }>,
931
+ * ): T1;
932
+ * }}
933
+ */
574
934
  static onPropChanged(options) {
575
- for (const [prop, callback] of Object.entries(options)) {
576
- if (this.propChangedCallbacks.has(prop)) {
577
- this.propChangedCallbacks.get(prop).push(callback);
935
+ const entries = Array.isArray(options) ? options : Object.entries(options);
936
+ const { propChangedCallbacks } = this;
937
+ for (const [prop, callback] of entries) {
938
+ if (propChangedCallbacks.has(prop)) {
939
+ propChangedCallbacks.get(prop).push(callback);
578
940
  } else {
579
- this.propChangedCallbacks.set(prop, [callback]);
941
+ propChangedCallbacks.set(prop, [callback]);
580
942
  }
581
943
  }
582
944
 
@@ -584,14 +946,33 @@ export default class CustomElement extends ICustomElement {
584
946
  return this;
585
947
  }
586
948
 
587
- /** @type {typeof ICustomElement['onAttributeChanged']} */
949
+ /**
950
+ * @type {{
951
+ * <
952
+ * T1 extends typeof CustomElement,
953
+ * T2 extends InstanceType<T1>
954
+ * >
955
+ * (
956
+ * this: T1,
957
+ * options: {
958
+ * [x:string]: (
959
+ * this: T2,
960
+ * oldValue: string,
961
+ * newValue: string,
962
+ * element: T2
963
+ * ) => void
964
+ * },
965
+ * ): T1;
966
+ * }}
967
+ */
588
968
  static onAttributeChanged(options) {
589
- for (const [name, callback] of Object.entries(options)) {
590
- const lcName = name.toLowerCase();
591
- if (this.attributeChangedCallbacks.has(lcName)) {
592
- this.attributeChangedCallbacks.get(lcName).push(callback);
969
+ const entries = Array.isArray(options) ? options : Object.entries(options);
970
+ const { attributeChangedCallbacks } = this;
971
+ for (const [name, callback] of entries) {
972
+ if (attributeChangedCallbacks.has(name)) {
973
+ attributeChangedCallbacks.get(name).push(callback);
593
974
  } else {
594
- this.attributeChangedCallbacks.set(lcName, [callback]);
975
+ attributeChangedCallbacks.set(name, [callback]);
595
976
  }
596
977
  }
597
978
 
@@ -614,7 +995,7 @@ export default class CustomElement extends ICustomElement {
614
995
  /** @type {Map<string,{stringValue:string, parsedValue:any}>} */
615
996
  _propAttributeCache;
616
997
 
617
- /** @type {import('./ICustomElement.js').CallbackArguments} */
998
+ /** @type {CallbackArguments} */
618
999
  _callbackArguments = null;
619
1000
 
620
1001
  /** @param {any[]} args */
@@ -636,11 +1017,12 @@ export default class CustomElement extends ICustomElement {
636
1017
  * @return {void}
637
1018
  */
638
1019
  this.render = this.composition.render(
639
- this,
1020
+ this.constructor.prototype,
640
1021
  this,
641
1022
  {
1023
+ defaults: this.constructor.prototype,
642
1024
  store: this,
643
- target: this.shadowRoot,
1025
+ shadowRoot: this.shadowRoot,
644
1026
  context: this,
645
1027
  },
646
1028
  );
@@ -650,15 +1032,27 @@ export default class CustomElement extends ICustomElement {
650
1032
  }
651
1033
  }
652
1034
 
653
- /** @type {InstanceType<typeof ICustomElement>['propChangedCallback']} */
1035
+ /**
1036
+ * @type {{
1037
+ * <
1038
+ * T extends CustomElement,
1039
+ * K extends string = string,
1040
+ * >(this:T,
1041
+ * name: K,
1042
+ * oldValue: K extends keyof T ? T[K] : unknown,
1043
+ * newValue: K extends keyof T ? T[K] : unknown,
1044
+ * changes?: K extends keyof T ? T[K] extends object ? Partial<T[K]> : T[K] : unknown): void;
1045
+ * }}
1046
+ */
654
1047
  propChangedCallback(name, oldValue, newValue, changes = newValue) {
655
1048
  if (!this.patching) {
656
1049
  this.render.byProp(name, changes, this);
657
1050
  // this.render({ [name]: changes });
658
1051
  }
659
1052
 
660
- if (this.static._propChangedCallbacks.has(name)) {
661
- for (const callback of this.static.propChangedCallbacks.get(name)) {
1053
+ const { _propChangedCallbacks } = this.static;
1054
+ if (_propChangedCallbacks.has(name)) {
1055
+ for (const callback of _propChangedCallbacks.get(name)) {
662
1056
  callback.call(this, oldValue, newValue, changes, this);
663
1057
  }
664
1058
  }
@@ -670,55 +1064,53 @@ export default class CustomElement extends ICustomElement {
670
1064
  * @param {string|null} newValue
671
1065
  */
672
1066
  attributeChangedCallback(name, oldValue, newValue) {
673
- const lcName = name.toLowerCase();
674
- if (this.static.attributeChangedCallbacks.has(lcName)) {
675
- for (const callback of this.static.attributeChangedCallbacks.get(lcName)) {
1067
+ const { attributeChangedCallbacks } = this.static;
1068
+ if (attributeChangedCallbacks.has(name)) {
1069
+ for (const callback of attributeChangedCallbacks.get(name)) {
676
1070
  callback.call(this, oldValue, newValue, this);
677
1071
  }
678
1072
  }
679
1073
 
680
1074
  // Array.find
681
- for (const config of this.static.propList.values()) {
682
- if (config.attr !== name) continue;
1075
+ const { attrList } = this.static;
1076
+ if (!attrList.has(name)) return;
683
1077
 
684
- if (config.reflect !== true && config.reflect !== 'read') return;
1078
+ const config = attrList.get(name);
685
1079
 
686
- if (config.attributeChangedCallback) {
687
- config.attributeChangedCallback.call(this, name, oldValue, newValue);
688
- return;
689
- }
1080
+ if (config.attributeChangedCallback) {
1081
+ config.attributeChangedCallback.call(this, name, oldValue, newValue);
1082
+ return;
1083
+ }
690
1084
 
691
- let cacheEntry;
692
- if (this.attributeCache.has(lcName)) {
693
- cacheEntry = this.attributeCache.get(lcName);
694
- if (cacheEntry.stringValue === newValue) return;
695
- }
1085
+ let cacheEntry;
1086
+ if (this.attributeCache.has(name)) {
1087
+ cacheEntry = this.attributeCache.get(name);
1088
+ if (cacheEntry.stringValue === newValue) return;
1089
+ }
696
1090
 
697
- // @ts-expect-error any
698
- const previousDataValue = this[config.key];
699
- const parsedValue = newValue === null
700
- ? config.nullParser(/** @type {null} */ (newValue))
701
- // Avoid Boolean('') === false
702
- : (config.type === 'boolean' ? true : config.parser(newValue));
1091
+ // @ts-expect-error any
1092
+ const previousDataValue = this[config.key];
1093
+ const parsedValue = newValue === null
1094
+ ? config.nullParser(/** @type {null} */ (newValue))
1095
+ // Avoid Boolean('') === false
1096
+ : (config.type === 'boolean' ? true : config.parser(newValue));
703
1097
 
704
- if (parsedValue === previousDataValue) {
705
- // No internal value change
706
- return;
707
- }
708
- // "Remember" that this attrValue equates to this data value
709
- // Avoids rewriting attribute later on data change event
710
- if (cacheEntry) {
711
- cacheEntry.stringValue = newValue;
712
- cacheEntry.parsedValue = parsedValue;
713
- } else {
714
- this.attributeCache.set(lcName, {
715
- stringValue: newValue, parsedValue,
716
- });
717
- }
718
- // @ts-expect-error any
719
- this[config.key] = parsedValue;
1098
+ if (parsedValue === previousDataValue) {
1099
+ // No internal value change
720
1100
  return;
721
1101
  }
1102
+ // "Remember" that this attrValue equates to this data value
1103
+ // Avoids rewriting attribute later on data change event
1104
+ if (cacheEntry) {
1105
+ cacheEntry.stringValue = newValue;
1106
+ cacheEntry.parsedValue = parsedValue;
1107
+ } else {
1108
+ this.attributeCache.set(name, {
1109
+ stringValue: newValue, parsedValue,
1110
+ });
1111
+ }
1112
+ // @ts-expect-error any
1113
+ this[config.key] = parsedValue;
722
1114
  }
723
1115
 
724
1116
  get #template() {
@@ -732,20 +1124,21 @@ export default class CustomElement extends ICustomElement {
732
1124
  * @param {any} changes
733
1125
  */
734
1126
  _onObserverPropertyChanged(name, oldValue, newValue, changes) {
735
- if (this.static.propList.has(name)) {
736
- const { reflect, attr } = this.static.propList.get(name);
1127
+ const { propList } = this.static;
1128
+ if (propList.has(name)) {
1129
+ const { reflect, attr } = propList.get(name);
737
1130
  if (attr && (reflect === true || reflect === 'write')) {
738
- const lcName = attr.toLowerCase();
739
1131
  /** @type {{stringValue:string, parsedValue:any}} */
740
1132
  let cacheEntry;
741
1133
  let needsWrite = false;
742
- if (this.attributeCache.has(lcName)) {
743
- cacheEntry = this.attributeCache.get(lcName);
1134
+ const { attributeCache } = this;
1135
+ if (attributeCache.has(attr)) {
1136
+ cacheEntry = attributeCache.get(attr);
744
1137
  needsWrite = (cacheEntry.parsedValue !== newValue);
745
1138
  } else {
746
1139
  // @ts-ignore skip cast
747
1140
  cacheEntry = {};
748
- this.attributeCache.set(lcName, cacheEntry);
1141
+ attributeCache.set(attr, cacheEntry);
749
1142
  needsWrite = true;
750
1143
  }
751
1144
  if (needsWrite) {
@@ -823,50 +1216,8 @@ export default class CustomElement extends ICustomElement {
823
1216
  }
824
1217
 
825
1218
  get attributeCache() {
826
- this._propAttributeCache ??= new Map();
827
- return this._propAttributeCache;
828
- }
829
-
830
- get tabIndex() {
831
- return super.tabIndex;
832
- }
833
-
834
- set tabIndex(value) {
835
- if (value === super.tabIndex && value !== -1) {
836
- // Non -1 value already set
837
- return;
838
- }
839
-
840
- if (this.delegatesFocus && document.activeElement === this) {
841
- if (this.getAttribute('tabindex') === value.toString()) {
842
- // Skip if possible
843
- return;
844
- }
845
-
846
- // Chrome blurs on tabindex changes with delegatesFocus
847
- // Fixed in Chrome 111
848
- // Remove this code ~June 2023
849
- // https://bugs.chromium.org/p/chromium/issues/detail?id=1346606
850
- /** @type {EventListener} */
851
- const listener = (e) => {
852
- e.stopImmediatePropagation();
853
- e.stopPropagation();
854
- if (e.type === 'blur') {
855
- console.warn('Chromium bug 1346606: Tabindex change caused blur. Giving focusing back.', this);
856
- this.focus();
857
- } else {
858
- console.warn('Chromium bug 1346606: Blocking focus event.', this);
859
- }
860
- };
861
- this.addEventListener('blur', listener, { capture: true, once: true });
862
- this.addEventListener('focus', listener, { capture: true, once: true });
863
- super.tabIndex = value;
864
- this.removeEventListener('blur', listener, { capture: true });
865
- this.removeEventListener('focus', listener, { capture: true });
866
- return;
867
- }
868
-
869
- super.tabIndex = value;
1219
+ // eslint-disable-next-line no-return-assign
1220
+ return (this._propAttributeCache ??= new Map());
870
1221
  }
871
1222
 
872
1223
  get static() { return /** @type {typeof CustomElement} */ (/** @type {unknown} */ (this.constructor)); }
@@ -877,6 +1228,7 @@ export default class CustomElement extends ICustomElement {
877
1228
  // eslint-disable-next-line no-return-assign
878
1229
  return this._callbackArguments ??= {
879
1230
  composition: this.#composition,
1231
+ refs: this.refs,
880
1232
  html: html.bind(this),
881
1233
  inline: addInlineFunction,
882
1234
  template: this.#template,