@shortfuse/materialdesignweb 0.7.6 → 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 (412) hide show
  1. package/README.md +87 -90
  2. package/bin/mdw-css.js +1 -1
  3. package/components/Badge.js +14 -7
  4. package/components/Body.js +3 -0
  5. package/components/BottomAppBar.js +4 -13
  6. package/components/BottomSheet.js +424 -0
  7. package/components/Box.js +20 -28
  8. package/components/Button.js +85 -79
  9. package/components/Button.md +9 -9
  10. package/components/Card.js +60 -72
  11. package/components/Checkbox.js +33 -42
  12. package/components/CheckboxIcon.js +11 -29
  13. package/components/Chip.js +13 -11
  14. package/components/Dialog.js +214 -394
  15. package/components/DialogActions.js +2 -2
  16. package/components/Display.js +55 -0
  17. package/components/Divider.js +3 -3
  18. package/components/Fab.js +83 -18
  19. package/components/FabContainer.js +48 -0
  20. package/components/FilterChip.js +35 -33
  21. package/components/Grid.js +176 -0
  22. package/components/Headline.js +5 -28
  23. package/components/Icon.js +61 -76
  24. package/components/IconButton.js +72 -126
  25. package/components/Input.js +859 -1
  26. package/components/InputChip.js +161 -0
  27. package/components/Label.js +3 -0
  28. package/components/List.js +4 -6
  29. package/components/ListItem.js +46 -30
  30. package/components/ListOption.js +86 -53
  31. package/components/Listbox.js +248 -0
  32. package/components/Menu.js +69 -528
  33. package/components/MenuItem.js +33 -36
  34. package/components/NavBar.js +49 -86
  35. package/components/NavDrawer.js +16 -15
  36. package/components/NavDrawerItem.js +4 -5
  37. package/components/NavItem.js +58 -41
  38. package/components/NavRail.js +30 -20
  39. package/components/NavRailItem.js +8 -3
  40. package/components/Page.js +105 -0
  41. package/components/Pane.js +11 -274
  42. package/components/Popup.js +29 -0
  43. package/components/Progress.js +24 -23
  44. package/components/Radio.js +40 -36
  45. package/components/RadioIcon.js +12 -16
  46. package/components/Ripple.js +13 -10
  47. package/components/Root.js +209 -0
  48. package/components/Scrim.js +87 -0
  49. package/components/Search.js +77 -0
  50. package/components/SegmentedButton.js +33 -45
  51. package/components/SegmentedButtonGroup.js +25 -13
  52. package/components/Select.js +10 -11
  53. package/components/Shape.js +5 -65
  54. package/components/SideSheet.js +308 -0
  55. package/components/Slider.js +108 -78
  56. package/components/Snackbar.js +26 -21
  57. package/components/SnackbarContainer.js +42 -0
  58. package/components/Surface.js +17 -12
  59. package/components/Switch.js +45 -24
  60. package/components/SwitchIcon.js +49 -39
  61. package/components/Tab.js +64 -43
  62. package/components/TabContent.js +5 -3
  63. package/components/TabList.js +62 -34
  64. package/components/TabPanel.js +11 -8
  65. package/components/Table.js +116 -0
  66. package/components/TextArea.js +54 -50
  67. package/components/Title.js +4 -9
  68. package/components/Tooltip.js +44 -22
  69. package/components/TopAppBar.js +68 -172
  70. package/constants/shapes.js +36 -0
  71. package/constants/typography.js +127 -0
  72. package/core/Composition.js +1164 -645
  73. package/core/CompositionAdapter.js +314 -0
  74. package/core/CustomElement.js +701 -286
  75. package/core/css.js +121 -15
  76. package/core/customTypes.js +157 -40
  77. package/core/dom.js +17 -11
  78. package/{utils → core}/jsonMergePatch.js +42 -18
  79. package/core/observe.js +343 -244
  80. package/core/optimizations.js +23 -0
  81. package/core/template.js +19 -56
  82. package/core/uid.js +13 -0
  83. package/dist/index.min.js +85 -184
  84. package/dist/index.min.js.map +4 -4
  85. package/dist/meta.json +1 -1
  86. package/dom/HTMLOptionsCollectionProxy.js +106 -0
  87. package/loaders/palette.js +13 -0
  88. package/loaders/theme.js +12 -0
  89. package/mixins/AriaReflectorMixin.js +53 -14
  90. package/mixins/AriaToolbarMixin.js +5 -3
  91. package/mixins/ControlMixin.js +92 -41
  92. package/mixins/DelegatesFocusMixin.js +54 -0
  93. package/mixins/DensityMixin.js +2 -3
  94. package/mixins/ElevationMixin.js +62 -0
  95. package/mixins/FlexableMixin.js +67 -39
  96. package/mixins/FormAssociatedMixin.js +71 -16
  97. package/mixins/HyperlinkMixin.js +66 -0
  98. package/mixins/InputMixin.js +205 -39
  99. package/mixins/KeyboardNavMixin.js +22 -7
  100. package/mixins/NavigationListenerMixin.js +33 -0
  101. package/mixins/PopupMixin.js +725 -0
  102. package/mixins/RTLObserverMixin.js +0 -1
  103. package/mixins/ResizeObserverMixin.js +16 -5
  104. package/mixins/RippleMixin.js +11 -10
  105. package/mixins/ScrollListenerMixin.js +42 -33
  106. package/mixins/SemiStickyMixin.js +97 -0
  107. package/mixins/ShapeMaskedMixin.js +117 -0
  108. package/mixins/ShapeMixin.js +17 -194
  109. package/mixins/StateMixin.js +80 -39
  110. package/mixins/TextFieldMixin.js +139 -183
  111. package/mixins/ThemableMixin.js +71 -161
  112. package/mixins/TooltipTriggerMixin.js +292 -366
  113. package/mixins/TouchTargetMixin.js +5 -4
  114. package/mixins/TypographyMixin.js +121 -0
  115. package/package.json +111 -71
  116. package/services/rtl.js +10 -0
  117. package/services/svgAlias.js +17 -0
  118. package/{theming/index.js → services/theme.js} +25 -175
  119. package/types/bin/mdw-css.d.ts +3 -0
  120. package/types/bin/mdw-css.d.ts.map +1 -0
  121. package/types/components/Badge.d.ts +39 -0
  122. package/types/components/Badge.d.ts.map +1 -0
  123. package/types/components/Body.d.ts +29 -0
  124. package/types/components/Body.d.ts.map +1 -0
  125. package/types/components/BottomAppBar.d.ts +73 -0
  126. package/types/components/BottomAppBar.d.ts.map +1 -0
  127. package/types/components/BottomSheet.d.ts +109 -0
  128. package/types/components/BottomSheet.d.ts.map +1 -0
  129. package/types/components/Box.d.ts +16 -0
  130. package/types/components/Box.d.ts.map +1 -0
  131. package/types/components/Button.d.ts +714 -0
  132. package/types/components/Button.d.ts.map +1 -0
  133. package/types/components/Card.d.ts +412 -0
  134. package/types/components/Card.d.ts.map +1 -0
  135. package/types/components/Checkbox.d.ts +205 -0
  136. package/types/components/Checkbox.d.ts.map +1 -0
  137. package/types/components/CheckboxIcon.d.ts +44 -0
  138. package/types/components/CheckboxIcon.d.ts.map +1 -0
  139. package/types/components/Chip.d.ts +1425 -0
  140. package/types/components/Chip.d.ts.map +1 -0
  141. package/types/components/Dialog.d.ts +286 -0
  142. package/types/components/Dialog.d.ts.map +1 -0
  143. package/types/components/DialogActions.d.ts +4 -0
  144. package/types/components/DialogActions.d.ts.map +1 -0
  145. package/types/components/Display.d.ts +45 -0
  146. package/types/components/Display.d.ts.map +1 -0
  147. package/types/components/Divider.d.ts +10 -0
  148. package/types/components/Divider.d.ts.map +1 -0
  149. package/types/components/Fab.d.ts +741 -0
  150. package/types/components/Fab.d.ts.map +1 -0
  151. package/types/components/FabContainer.d.ts +10 -0
  152. package/types/components/FabContainer.d.ts.map +1 -0
  153. package/types/components/FilterChip.d.ts +4283 -0
  154. package/types/components/FilterChip.d.ts.map +1 -0
  155. package/types/components/Grid.d.ts +37 -0
  156. package/types/components/Grid.d.ts.map +1 -0
  157. package/types/components/Headline.d.ts +47 -0
  158. package/types/components/Headline.d.ts.map +1 -0
  159. package/types/components/Icon.d.ts +103 -0
  160. package/types/components/Icon.d.ts.map +1 -0
  161. package/types/components/IconButton.d.ts +1486 -0
  162. package/types/components/IconButton.d.ts.map +1 -0
  163. package/types/components/Input.d.ts +51288 -0
  164. package/types/components/Input.d.ts.map +1 -0
  165. package/types/components/InputChip.d.ts +243 -0
  166. package/types/components/InputChip.d.ts.map +1 -0
  167. package/types/components/Label.d.ts +29 -0
  168. package/types/components/Label.d.ts.map +1 -0
  169. package/types/components/List.d.ts +31 -0
  170. package/types/components/List.d.ts.map +1 -0
  171. package/types/components/ListItem.d.ts +349 -0
  172. package/types/components/ListItem.d.ts.map +1 -0
  173. package/types/components/ListOption.d.ts +1493 -0
  174. package/types/components/ListOption.d.ts.map +1 -0
  175. package/types/components/Listbox.d.ts +12012 -0
  176. package/types/components/Listbox.d.ts.map +1 -0
  177. package/types/components/Menu.d.ts +119 -0
  178. package/types/components/Menu.d.ts.map +1 -0
  179. package/types/components/MenuItem.d.ts +3109 -0
  180. package/types/components/MenuItem.d.ts.map +1 -0
  181. package/types/components/NavBar.d.ts +18 -0
  182. package/types/components/NavBar.d.ts.map +1 -0
  183. package/types/components/NavBarItem.d.ts +186 -0
  184. package/types/components/NavBarItem.d.ts.map +1 -0
  185. package/types/components/NavDrawer.d.ts +108 -0
  186. package/types/components/NavDrawer.d.ts.map +1 -0
  187. package/types/components/NavDrawerItem.d.ts +186 -0
  188. package/types/components/NavDrawerItem.d.ts.map +1 -0
  189. package/types/components/NavItem.d.ts +190 -0
  190. package/types/components/NavItem.d.ts.map +1 -0
  191. package/types/components/NavRail.d.ts +109 -0
  192. package/types/components/NavRail.d.ts.map +1 -0
  193. package/types/components/NavRailItem.d.ts +186 -0
  194. package/types/components/NavRailItem.d.ts.map +1 -0
  195. package/types/components/Page.d.ts +24 -0
  196. package/types/components/Page.d.ts.map +1 -0
  197. package/types/components/Pane.d.ts +44 -0
  198. package/types/components/Pane.d.ts.map +1 -0
  199. package/types/components/Popup.d.ts +76 -0
  200. package/types/components/Popup.d.ts.map +1 -0
  201. package/types/components/Progress.d.ts +19 -0
  202. package/types/components/Progress.d.ts.map +1 -0
  203. package/types/components/Radio.d.ts +199 -0
  204. package/types/components/Radio.d.ts.map +1 -0
  205. package/types/components/RadioIcon.d.ts +46 -0
  206. package/types/components/RadioIcon.d.ts.map +1 -0
  207. package/types/components/Ripple.d.ts +34 -0
  208. package/types/components/Ripple.d.ts.map +1 -0
  209. package/types/components/Root.d.ts +68 -0
  210. package/types/components/Root.d.ts.map +1 -0
  211. package/types/components/Scrim.d.ts +6 -0
  212. package/types/components/Scrim.d.ts.map +1 -0
  213. package/types/components/Search.d.ts +16 -0
  214. package/types/components/Search.d.ts.map +1 -0
  215. package/types/components/SegmentedButton.d.ts +718 -0
  216. package/types/components/SegmentedButton.d.ts.map +1 -0
  217. package/types/components/SegmentedButtonGroup.d.ts +44 -0
  218. package/types/components/SegmentedButtonGroup.d.ts.map +1 -0
  219. package/types/components/Select.d.ts +1361 -0
  220. package/types/components/Select.d.ts.map +1 -0
  221. package/types/components/Shape.d.ts +10 -0
  222. package/types/components/Shape.d.ts.map +1 -0
  223. package/types/components/SideSheet.d.ts +106 -0
  224. package/types/components/SideSheet.d.ts.map +1 -0
  225. package/types/components/Slider.d.ts +382 -0
  226. package/types/components/Slider.d.ts.map +1 -0
  227. package/types/components/Snackbar.d.ts +65 -0
  228. package/types/components/Snackbar.d.ts.map +1 -0
  229. package/types/components/SnackbarContainer.d.ts +6 -0
  230. package/types/components/SnackbarContainer.d.ts.map +1 -0
  231. package/types/components/Surface.d.ts +45 -0
  232. package/types/components/Surface.d.ts.map +1 -0
  233. package/types/components/Switch.d.ts +183 -0
  234. package/types/components/Switch.d.ts.map +1 -0
  235. package/types/components/SwitchIcon.d.ts +169 -0
  236. package/types/components/SwitchIcon.d.ts.map +1 -0
  237. package/types/components/Tab.d.ts +879 -0
  238. package/types/components/Tab.d.ts.map +1 -0
  239. package/types/components/TabContent.d.ts +122 -0
  240. package/types/components/TabContent.d.ts.map +1 -0
  241. package/types/components/TabList.d.ts +6266 -0
  242. package/types/components/TabList.d.ts.map +1 -0
  243. package/types/components/TabPanel.d.ts +28 -0
  244. package/types/components/TabPanel.d.ts.map +1 -0
  245. package/types/components/Table.d.ts +2 -0
  246. package/types/components/Table.d.ts.map +1 -0
  247. package/types/components/TextArea.d.ts +1394 -0
  248. package/types/components/TextArea.d.ts.map +1 -0
  249. package/types/components/Title.d.ts +47 -0
  250. package/types/components/Title.d.ts.map +1 -0
  251. package/types/components/Tooltip.d.ts +49 -0
  252. package/types/components/Tooltip.d.ts.map +1 -0
  253. package/types/components/TopAppBar.d.ts +130 -0
  254. package/types/components/TopAppBar.d.ts.map +1 -0
  255. package/types/constants/colorKeywords.d.ts +2 -0
  256. package/types/constants/colorKeywords.d.ts.map +1 -0
  257. package/types/constants/shapes.d.ts +38 -0
  258. package/types/constants/shapes.d.ts.map +1 -0
  259. package/types/constants/typography.d.ts +212 -0
  260. package/types/constants/typography.d.ts.map +1 -0
  261. package/types/core/Composition.d.ts +252 -0
  262. package/types/core/Composition.d.ts.map +1 -0
  263. package/types/core/CompositionAdapter.d.ts +92 -0
  264. package/types/core/CompositionAdapter.d.ts.map +1 -0
  265. package/types/core/CustomElement.d.ts +302 -0
  266. package/types/core/CustomElement.d.ts.map +1 -0
  267. package/types/core/css.d.ts +44 -0
  268. package/types/core/css.d.ts.map +1 -0
  269. package/types/core/customTypes.d.ts +26 -0
  270. package/types/core/customTypes.d.ts.map +1 -0
  271. package/types/core/dom.d.ts +32 -0
  272. package/types/core/dom.d.ts.map +1 -0
  273. package/types/core/jsonMergePatch.d.ts +31 -0
  274. package/types/core/jsonMergePatch.d.ts.map +1 -0
  275. package/types/core/observe.d.ts +113 -0
  276. package/types/core/observe.d.ts.map +1 -0
  277. package/types/core/optimizations.d.ts +7 -0
  278. package/types/core/optimizations.d.ts.map +1 -0
  279. package/types/core/template.d.ts +47 -0
  280. package/types/core/template.d.ts.map +1 -0
  281. package/types/core/uid.d.ts +6 -0
  282. package/types/core/uid.d.ts.map +1 -0
  283. package/types/dom/HTMLOptionsCollectionProxy.d.ts +18 -0
  284. package/types/dom/HTMLOptionsCollectionProxy.d.ts.map +1 -0
  285. package/types/index.d.ts +88 -0
  286. package/types/index.d.ts.map +1 -0
  287. package/types/loaders/palette.d.ts +2 -0
  288. package/types/loaders/palette.d.ts.map +1 -0
  289. package/types/loaders/theme.d.ts +2 -0
  290. package/types/loaders/theme.d.ts.map +1 -0
  291. package/types/mixins/AriaReflectorMixin.d.ts +23 -0
  292. package/types/mixins/AriaReflectorMixin.d.ts.map +1 -0
  293. package/types/mixins/AriaToolbarMixin.d.ts +32 -0
  294. package/types/mixins/AriaToolbarMixin.d.ts.map +1 -0
  295. package/types/mixins/ControlMixin.d.ts +124 -0
  296. package/types/mixins/ControlMixin.d.ts.map +1 -0
  297. package/types/mixins/DelegatesFocusMixin.d.ts +5 -0
  298. package/types/mixins/DelegatesFocusMixin.d.ts.map +1 -0
  299. package/types/mixins/DensityMixin.d.ts +5 -0
  300. package/types/mixins/DensityMixin.d.ts.map +1 -0
  301. package/types/mixins/ElevationMixin.d.ts +33 -0
  302. package/types/mixins/ElevationMixin.d.ts.map +1 -0
  303. package/types/mixins/FlexableMixin.d.ts +13 -0
  304. package/types/mixins/FlexableMixin.d.ts.map +1 -0
  305. package/types/mixins/FormAssociatedMixin.d.ts +122 -0
  306. package/types/mixins/FormAssociatedMixin.d.ts.map +1 -0
  307. package/types/mixins/HyperlinkMixin.d.ts +22 -0
  308. package/types/mixins/HyperlinkMixin.d.ts.map +1 -0
  309. package/types/mixins/InputMixin.d.ts +179 -0
  310. package/types/mixins/InputMixin.d.ts.map +1 -0
  311. package/types/mixins/KeyboardNavMixin.d.ts +47 -0
  312. package/types/mixins/KeyboardNavMixin.d.ts.map +1 -0
  313. package/types/mixins/NavigationListenerMixin.d.ts +8 -0
  314. package/types/mixins/NavigationListenerMixin.d.ts.map +1 -0
  315. package/types/mixins/PopupMixin.d.ts +82 -0
  316. package/types/mixins/PopupMixin.d.ts.map +1 -0
  317. package/types/mixins/RTLObserverMixin.d.ts +7 -0
  318. package/types/mixins/RTLObserverMixin.d.ts.map +1 -0
  319. package/types/mixins/ResizeObserverMixin.d.ts +12 -0
  320. package/types/mixins/ResizeObserverMixin.d.ts.map +1 -0
  321. package/types/mixins/RippleMixin.d.ts +92 -0
  322. package/types/mixins/RippleMixin.d.ts.map +1 -0
  323. package/types/mixins/ScrollListenerMixin.d.ts +41 -0
  324. package/types/mixins/ScrollListenerMixin.d.ts.map +1 -0
  325. package/types/mixins/SemiStickyMixin.d.ts +50 -0
  326. package/types/mixins/SemiStickyMixin.d.ts.map +1 -0
  327. package/types/mixins/ShapeMaskedMixin.d.ts +9 -0
  328. package/types/mixins/ShapeMaskedMixin.d.ts.map +1 -0
  329. package/types/mixins/ShapeMixin.d.ts +38 -0
  330. package/types/mixins/ShapeMixin.d.ts.map +1 -0
  331. package/types/mixins/StateMixin.d.ts +27 -0
  332. package/types/mixins/StateMixin.d.ts.map +1 -0
  333. package/types/mixins/TextFieldMixin.d.ts +1354 -0
  334. package/types/mixins/TextFieldMixin.d.ts.map +1 -0
  335. package/types/mixins/ThemableMixin.d.ts +9 -0
  336. package/types/mixins/ThemableMixin.d.ts.map +1 -0
  337. package/types/mixins/TooltipTriggerMixin.d.ts +106 -0
  338. package/types/mixins/TooltipTriggerMixin.d.ts.map +1 -0
  339. package/types/mixins/TouchTargetMixin.d.ts +3 -0
  340. package/types/mixins/TouchTargetMixin.d.ts.map +1 -0
  341. package/types/mixins/TypographyMixin.d.ts +17 -0
  342. package/types/mixins/TypographyMixin.d.ts.map +1 -0
  343. package/types/services/rtl.d.ts +3 -0
  344. package/types/services/rtl.d.ts.map +1 -0
  345. package/types/services/svgAlias.d.ts +13 -0
  346. package/types/services/svgAlias.d.ts.map +1 -0
  347. package/types/services/theme.d.ts +45 -0
  348. package/types/services/theme.d.ts.map +1 -0
  349. package/types/utils/cli.d.ts +3 -0
  350. package/types/utils/cli.d.ts.map +1 -0
  351. package/types/utils/function.d.ts +3 -0
  352. package/types/utils/function.d.ts.map +1 -0
  353. package/types/utils/jsx-runtime.d.ts +20 -0
  354. package/types/utils/jsx-runtime.d.ts.map +1 -0
  355. package/types/utils/material-color/blend.d.ts +34 -0
  356. package/types/utils/material-color/blend.d.ts.map +1 -0
  357. package/types/utils/material-color/hct/Cam16.d.ts +142 -0
  358. package/types/utils/material-color/hct/Cam16.d.ts.map +1 -0
  359. package/types/utils/material-color/hct/Hct.d.ts +93 -0
  360. package/types/utils/material-color/hct/Hct.d.ts.map +1 -0
  361. package/types/utils/material-color/hct/ViewingConditions.d.ts +69 -0
  362. package/types/utils/material-color/hct/ViewingConditions.d.ts.map +1 -0
  363. package/types/utils/material-color/hct/hctSolver.d.ts +30 -0
  364. package/types/utils/material-color/hct/hctSolver.d.ts.map +1 -0
  365. package/types/utils/material-color/helper.d.ts +8 -0
  366. package/types/utils/material-color/helper.d.ts.map +1 -0
  367. package/types/utils/material-color/palettes/CorePalette.d.ts +75 -0
  368. package/types/utils/material-color/palettes/CorePalette.d.ts.map +1 -0
  369. package/types/utils/material-color/palettes/TonalPalette.d.ts +38 -0
  370. package/types/utils/material-color/palettes/TonalPalette.d.ts.map +1 -0
  371. package/types/utils/material-color/scheme/Scheme.d.ts +264 -0
  372. package/types/utils/material-color/scheme/Scheme.d.ts.map +1 -0
  373. package/types/utils/material-color/utils/color.d.ts +172 -0
  374. package/types/utils/material-color/utils/color.d.ts.map +1 -0
  375. package/types/utils/material-color/utils/math.d.ts +94 -0
  376. package/types/utils/material-color/utils/math.d.ts.map +1 -0
  377. package/types/utils/pixelmatch.d.ts +22 -0
  378. package/types/utils/pixelmatch.d.ts.map +1 -0
  379. package/types/utils/popup.d.ts +106 -0
  380. package/types/utils/popup.d.ts.map +1 -0
  381. package/types/utils/searchParams.d.ts +3 -0
  382. package/types/utils/searchParams.d.ts.map +1 -0
  383. package/types/utils/svg.d.ts +7 -0
  384. package/types/utils/svg.d.ts.map +1 -0
  385. package/utils/{hct → material-color}/blend.js +8 -10
  386. package/utils/{hct → material-color/hct}/Cam16.js +196 -69
  387. package/utils/{hct → material-color/hct}/Hct.js +61 -19
  388. package/utils/{hct → material-color/hct}/ViewingConditions.js +3 -3
  389. package/utils/{hct → material-color/hct}/hctSolver.js +9 -16
  390. package/utils/{hct → material-color}/helper.js +11 -18
  391. package/utils/{hct → material-color/palettes}/CorePalette.js +79 -19
  392. package/utils/{hct → material-color/palettes}/TonalPalette.js +12 -4
  393. package/utils/material-color/scheme/Scheme.js +376 -0
  394. package/utils/{hct/colorUtils.js → material-color/utils/color.js} +61 -1
  395. package/utils/pixelmatch.js +360 -0
  396. package/utils/popup.js +127 -30
  397. package/utils/searchParams.js +19 -0
  398. package/components/ExtendedFab.js +0 -36
  399. package/components/Layout.js +0 -35
  400. package/components/ListSelect.js +0 -220
  401. package/components/Nav.js +0 -40
  402. package/components/Option.js +0 -91
  403. package/core/ICustomElement.d.ts +0 -291
  404. package/core/ICustomElement.js +0 -1
  405. package/core/identify.js +0 -40
  406. package/core/typings.d.ts +0 -136
  407. package/core/typings.js +0 -1
  408. package/mixins/SurfaceMixin.js +0 -181
  409. package/theming/loader.js +0 -22
  410. package/utils/hct/Scheme.js +0 -587
  411. /package/{utils/color_keywords.js → constants/colorKeywords.js} +0 -0
  412. /package/utils/{hct/mathUtils.js → material-color/utils/math.js} +0 -0
@@ -1,10 +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
+ import { applyMergePatch } from './jsonMergePatch.js';
6
7
  import { defineObservableProperty } from './observe.js';
7
- 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
+ */
8
115
 
9
116
  /**
10
117
  * @template {abstract new (...args: any) => unknown} T
@@ -32,57 +139,49 @@ export function cloneAttributeCallback(name, target) {
32
139
  };
33
140
  }
34
141
 
35
- const EVENT_PREFIX_REGEX = /^([*1~]+)?(.*)$/;
36
-
37
142
  /**
38
143
  * Web Component that can cache templates for minification or performance
39
144
  */
40
- export default class CustomElement extends ICustomElement {
145
+ export default class CustomElement extends HTMLElement {
41
146
  /** @type {string} */
42
147
  static elementName;
43
148
 
44
149
  /** @return {Iterable<string>} */
45
150
  static get observedAttributes() {
46
- const s = new Set();
47
- for (const config of this.propList.values()) {
48
- if (config.reflect === true || config.reflect === 'read') {
49
- s.add(config.attr);
50
- }
51
- }
52
- return s;
151
+ return this.attrList.keys();
53
152
  }
54
153
 
55
154
  /** @type {import('./Composition.js').Compositor<?>} */
56
155
  compose() {
57
- if (this.#composition) {
58
- console.warn('Already composed. Generating *new* composition...');
59
- }
60
- this.#composition = new Composition();
61
- return this.#composition;
156
+ // eslint-disable-next-line no-return-assign
157
+ return (this.#composition ??= new Composition());
62
158
  }
63
159
 
64
160
  /** @type {Composition<?>} */
65
161
  static _composition = null;
66
162
 
67
- /** @type {Map<string, import('./typings.js').ObserverConfiguration<?,?,?>>} */
163
+ /** @type {Map<string, import('./observe.js').ObserverConfiguration<?,?,?>>} */
68
164
  static _props = new Map();
69
165
 
166
+ /** @type {Map<string, import('./observe.js').ObserverConfiguration<?,?,?>>} */
167
+ static _attrs = new Map();
168
+
70
169
  /** @type {Map<string, Function[]>} */
71
170
  static _propChangedCallbacks = new Map();
72
171
 
73
172
  /** @type {Map<string, Function[]>} */
74
173
  static _attributeChangedCallbacks = new Map();
75
174
 
76
- /** @type {typeof ICustomElement._onComposeCallbacks} */
175
+ /** @type {((callback: CallbackArguments) => any)[]} */
77
176
  static _onComposeCallbacks = [];
78
177
 
79
- /** @type {typeof ICustomElement._onConnectedCallbacks} */
178
+ /** @type {((callback: CallbackArguments) => any)[]} */
80
179
  static _onConnectedCallbacks = [];
81
180
 
82
- /** @type {typeof ICustomElement._onDisconnectedCallbacks} */
181
+ /** @type {((callback: CallbackArguments) => any)[]} */
83
182
  static _onDisconnectedCallbacks = [];
84
183
 
85
- /** @type {typeof ICustomElement._onConstructedCallbacks} */
184
+ /** @type {((callback: CallbackArguments) => any)[]} */
86
185
  static _onConstructedCallbacks = [];
87
186
 
88
187
  static interpolatesTemplate = true;
@@ -102,68 +201,189 @@ export default class CustomElement extends ICustomElement {
102
201
  /** @type {Map<string, typeof CustomElement>} */
103
202
  static registrations = new Map();
104
203
 
105
- /** @type {typeof ICustomElement.expressions} */
106
- 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);
107
271
 
108
- /** @type {typeof ICustomElement.methods} */
109
272
  static methods = this.set;
110
273
 
111
- /** @type {typeof ICustomElement.overrides} */
112
- 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);
113
309
 
114
- /** @type {typeof ICustomElement.props} */
115
- static props = this.observe;
310
+ static idl = this.prop;
116
311
 
117
312
  /**
118
- * @template {typeof CustomElement} T
119
313
  * @this T
314
+ * @template {typeof CustomElement} T
120
315
  * @template {keyof T} K
121
316
  * @param {K} collection
122
317
  * @param {T[K] extends (infer R)[] ? R : never} callback
123
318
  */
124
319
  static _addCallback(collection, callback) {
125
320
  if (!this.hasOwnProperty(collection)) {
126
- this[collection] = [
127
- ...this[collection],
128
- ];
321
+ // @ts-expect-error not typed
322
+ this[collection] = [...this[collection], callback];
323
+ return;
129
324
  }
325
+ // @ts-expect-error any
130
326
  this[collection].push(callback);
131
327
  }
132
328
 
133
329
  /**
134
330
  * Append parts to composition
135
- * @type {typeof ICustomElement.append}
331
+ * @type {{
332
+ * <
333
+ * T extends typeof CustomElement,
334
+ * >
335
+ * (this: T, ...parts: ConstructorParameters<typeof Composition<InstanceType<T>>>): T;
336
+ * }}
136
337
  */
137
338
  static append(...parts) {
138
- this.on({
139
- composed({ composition }) {
140
- // console.debug('onComposed:append', ...parts);
141
- composition.append(...parts);
142
- },
339
+ this._addCallback('_onComposeCallbacks', ({ composition }) => {
340
+ composition.append(...parts);
143
341
  });
144
342
  // @ts-expect-error Can't cast T
145
343
  return this;
146
344
  }
147
345
 
148
346
  /**
149
- * Appends styles to composition
150
- * @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
+ * }}
151
357
  */
152
- static css(array, ...substitutions) {
153
- if (Array.isArray(array)) {
154
- // @ts-expect-error Complex cast
155
- this.append(css(array, ...substitutions));
156
- } else {
157
- // @ts-expect-error Complex cast
158
- this.append(array, ...substitutions);
159
- }
358
+ static recompose(callback) {
359
+ this._addCallback('_onComposeCallbacks', callback);
160
360
  // @ts-expect-error Can't cast T
161
361
  return this;
162
362
  }
163
363
 
164
- /** @type {typeof ICustomElement['setSchema']} */
165
- static setSchema(schema) {
166
- 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
+
167
387
  // @ts-expect-error Can't cast T
168
388
  return this;
169
389
  }
@@ -172,31 +392,35 @@ export default class CustomElement extends ICustomElement {
172
392
  * Registers class asynchronously at end of current event loop cycle
173
393
  * via `queueMicrotask`. If class is registered before then,
174
394
  * does nothing.
175
- * @type {typeof ICustomElement['autoRegister']}
395
+ * @type {{
396
+ * <T extends typeof CustomElement>(this: T, elementName: string): T;
397
+ * }}
176
398
  */
177
399
  static autoRegister(elementName) {
178
- if (elementName) {
179
- this.elementName = elementName;
400
+ if (this.hasOwnProperty('defined') && this.defined) {
401
+ console.warn(this.elementName, 'already registered.');
402
+ // @ts-expect-error Can't cast T
403
+ return this;
180
404
  }
181
- queueMicrotask(() => {
182
- if (this.autoRegistration) {
183
- this.register();
184
- }
185
- });
405
+ this.register(elementName);
186
406
  // @ts-expect-error Can't cast T
187
407
  return this;
188
408
  }
189
409
 
190
410
  /**
191
411
  * Appends DocumentFragment to composition
192
- * @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
+ * }}
193
419
  */
194
420
  static html(strings, ...substitutions) {
195
- this.on({
196
- composed({ composition }) {
421
+ this._addCallback('_onComposeCallbacks', ({ composition }) => {
197
422
  // console.log('onComposed:html', strings);
198
- composition.append(html(strings, ...substitutions));
199
- },
423
+ composition.append(html(strings, ...substitutions));
200
424
  });
201
425
  // @ts-expect-error Can't cast T
202
426
  return this;
@@ -205,28 +429,28 @@ export default class CustomElement extends ICustomElement {
205
429
  /**
206
430
  * Extends base class into a new class.
207
431
  * Use to avoid mutating base class.
208
- * TODO: Add constructor arguments typing
209
- * @type {typeof ICustomElement.extend}
210
- */
211
- static extend() {
212
- // @ts-expect-error Can't cast T
213
- return class extends this {};
214
- }
215
-
216
- /**
217
- * Extends base class into a new class.
218
- * Use to avoid mutating base class.
219
- * TODO: Add constructor arguments typing
220
- * @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
+ * }}
221
436
  */
222
- static tsClassFix() {
437
+ static extend(customExtender) {
223
438
  // @ts-expect-error Can't cast T
224
- return this;
439
+ return customExtender ? customExtender(this) : class extends this {};
225
440
  }
226
441
 
227
442
  /**
228
443
  * Assigns static values to class
229
- * @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
+ * }}
230
454
  */
231
455
  static setStatic(source) {
232
456
  Object.assign(this, source);
@@ -236,7 +460,15 @@ export default class CustomElement extends ICustomElement {
236
460
 
237
461
  /**
238
462
  * Assigns values directly to all instances (via prototype)
239
- * @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
+ * }}
240
472
  */
241
473
  static readonly(source, options) {
242
474
  // @ts-expect-error Can't cast T
@@ -245,13 +477,21 @@ export default class CustomElement extends ICustomElement {
245
477
 
246
478
  /**
247
479
  * Assigns values directly to all instances (via prototype)
248
- * @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
+ * }}
249
489
  */
250
490
  static set(source, options) {
251
491
  Object.defineProperties(
252
492
  this.prototype,
253
- Object.fromEntries(
254
- Object.entries(source).map(([name, value]) => {
493
+ Object.fromEntries([
494
+ ...Object.entries(source).map(([name, value]) => {
255
495
  // Tap into .map() to avoid double iteration
256
496
  // Property may be redefined observable
257
497
  this.undefine(name);
@@ -266,7 +506,17 @@ export default class CustomElement extends ICustomElement {
266
506
  },
267
507
  ];
268
508
  }),
269
- ),
509
+ ...Object.getOwnPropertySymbols(source).map((symbol) => [
510
+ symbol,
511
+ {
512
+ enumerable: false,
513
+ configurable: true,
514
+ value: source[symbol],
515
+ writable: true,
516
+ ...options,
517
+ },
518
+ ]),
519
+ ]),
270
520
  );
271
521
  // @ts-expect-error Can't cast T
272
522
  return this;
@@ -274,7 +524,14 @@ export default class CustomElement extends ICustomElement {
274
524
 
275
525
  /**
276
526
  * Returns result of calling mixin with current class
277
- * @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
+ * }}
278
535
  */
279
536
  static mixin(mixin) {
280
537
  return mixin(this);
@@ -282,15 +539,11 @@ export default class CustomElement extends ICustomElement {
282
539
 
283
540
  /**
284
541
  * Registers class with window.customElements synchronously
285
- * @type {typeof ICustomElement['register']}
542
+ * @type {{
543
+ * <T extends typeof CustomElement>(this: T, elementName?: string, force?: boolean): T;
544
+ * }}
286
545
  */
287
- static register(elementName, force = false) {
288
- if (this.hasOwnProperty('defined') && this.defined && !force) {
289
- console.warn(this.elementName, 'already registered.');
290
- // @ts-expect-error Can't cast T
291
- return this;
292
- }
293
-
546
+ static register(elementName) {
294
547
  if (elementName) {
295
548
  this.elementName = elementName;
296
549
  }
@@ -309,6 +562,13 @@ export default class CustomElement extends ICustomElement {
309
562
  return this._props;
310
563
  }
311
564
 
565
+ static get attrList() {
566
+ if (!this.hasOwnProperty('_attrs')) {
567
+ this._attrs = new Map(this._attrs);
568
+ }
569
+ return this._attrs;
570
+ }
571
+
312
572
  static get propChangedCallbacks() {
313
573
  if (!this.hasOwnProperty('_propChangedCallbacks')) {
314
574
  // structuredClone()
@@ -334,55 +594,82 @@ export default class CustomElement extends ICustomElement {
334
594
 
335
595
  /**
336
596
  * Creates observable property on instances (via prototype)
337
- * @template {import('./typings.js').ObserverPropertyType} [T1=null]
338
- * @template {import('./typings.js').ObserverPropertyType} [T2=null]
339
- * @template {any} [T3=null]
340
- * @param {string} name
341
- * @param {T1|import('./typings.js').ObserverOptions<T2,T3>} [typeOrOptions='string']
342
- * @return {(
343
- * T3 extends null ?
344
- * T2 extends null ?
345
- * T1 extends null ?
346
- * string
347
- * : import('./typings.js').ParsedObserverPropertyType<T1>
348
- * : import('./typings.js').ParsedObserverPropertyType<T2>
349
- * : T3
350
- * )}
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
+ * }}
351
616
  */
352
617
  static prop(name, typeOrOptions) {
353
618
  // TODO: Cache and save configuration for reuse (mixins)
354
- /** @type {import('./typings.js').ObserverOptions<?,?>} */
355
- const options = {
356
- ...((typeof typeOrOptions === 'string') ? { type: typeOrOptions } : typeOrOptions),
357
- };
358
-
359
- const customCallback = options.changedCallback;
619
+ const config = defineObservableProperty(
620
+ /** @type {any} */ (this.prototype),
621
+ name,
622
+ /** @type {any} */ (typeOrOptions),
623
+ );
360
624
 
361
- if (customCallback) {
362
- // Move callback to later in stack for attribute-based changes as well
363
- this.onPropChanged({ [name]: customCallback });
625
+ const { changedCallback, attr, reflect, watchers } = config;
626
+ if (changedCallback) {
627
+ watchers.push([name, changedCallback]);
364
628
  }
365
-
366
629
  // TODO: Inspect possible closure bloat
367
- options.changedCallback = function wrappedChangedCallback(oldValue, newValue, changes) {
630
+ config.changedCallback = function wrappedChangedCallback(oldValue, newValue, changes) {
368
631
  this._onObserverPropertyChanged.call(this, name, oldValue, newValue, changes);
369
632
  };
370
633
 
371
- const config = defineObservableProperty(this.prototype, name, options);
372
-
373
634
  this.propList.set(name, config);
374
- for (const [prop, callback] of config.watchers) {
375
- this.on(`${prop}Changed`, callback);
635
+
636
+ if (attr && (reflect === true || reflect === 'read')) {
637
+ this.attrList.set(attr, config);
376
638
  }
377
639
 
378
- return config.INIT_SYMBOL;
640
+ this.onPropChanged(watchers);
641
+
642
+ // @ts-expect-error Can't cast T
643
+ return this;
379
644
  }
380
645
 
381
646
  /**
382
647
  * Define properties on instances via Object.defineProperties().
383
648
  * Automatically sets property non-enumerable if name begins with `_`.
384
649
  * Functions will be remapped as getters
385
- * @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
+ * }}
386
673
  */
387
674
  static define(props) {
388
675
  Object.defineProperties(
@@ -414,43 +701,68 @@ export default class CustomElement extends ICustomElement {
414
701
 
415
702
  static undefine(name) {
416
703
  Reflect.deleteProperty(this.prototype, name);
417
- const config = this.propList.get(name);
418
- if (config && config.watchers.length) {
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)) {
419
707
  const propWatchers = this.propChangedCallbacks.get(name);
420
- if (propWatchers) {
421
- for (const watcher of config.watchers) {
422
- const index = propWatchers.indexOf(watcher);
423
- if (index !== -1) {
424
- console.warn('Unwatching', name);
425
- propWatchers.splice(index, 1);
426
- }
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);
427
713
  }
428
714
  }
429
715
  }
716
+ if (attr && (reflect === true || reflect === 'read')) {
717
+ this.attrList.delete(attr);
718
+ }
430
719
  this.propList.delete(name);
720
+
431
721
  return this;
432
722
  }
433
723
 
434
724
  /**
435
725
  * Creates observable properties on instances
436
- * @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
+ * }}
437
744
  */
438
745
  static observe(props) {
439
746
  for (const [name, typeOrOptions] of Object.entries(props ?? {})) {
440
- if (typeof typeOrOptions === 'function') {
441
- this.prop(name, {
442
- reflect: false,
443
- get: typeOrOptions,
444
- });
445
- } else {
446
- this.prop(name, typeOrOptions);
447
- }
747
+ /** @type {any} */
748
+ const options = (typeof typeOrOptions === 'function')
749
+ ? { reflect: false, get: typeOrOptions }
750
+ : typeOrOptions;
751
+
752
+ this.prop(name, options);
448
753
  }
449
754
  // @ts-expect-error Can't cast T
450
755
  return this;
451
756
  }
452
757
 
453
- /** @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
+ */
454
766
  static defineStatic(props) {
455
767
  for (const [name, typeOrOptions] of Object.entries(props ?? {})) {
456
768
  const options = (typeof typeOrOptions === 'function')
@@ -467,12 +779,35 @@ export default class CustomElement extends ICustomElement {
467
779
  return this;
468
780
  }
469
781
 
470
- /** @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
+ */
471
792
  static events(listeners, options) {
472
793
  this.on({
473
794
  composed({ composition }) {
474
795
  for (const [key, listenerOptions] of Object.entries(listeners)) {
475
- const [, flags, type] = key.match(EVENT_PREFIX_REGEX);
796
+ const [, flags, type] = key.match(/^([*1~]+)?(.*)$/);
797
+ // TODO: Make abstract
798
+ let prop;
799
+ /** @type {string[]} */
800
+ let deepProp = [];
801
+ if (typeof listenerOptions === 'string') {
802
+ const parsedProps = listenerOptions.split('.');
803
+ if (parsedProps.length === 1) {
804
+ prop = listenerOptions;
805
+ deepProp = [];
806
+ } else {
807
+ prop = parsedProps[0];
808
+ deepProp = parsedProps;
809
+ }
810
+ }
476
811
  composition.addCompositionEventListener({
477
812
  type,
478
813
  once: flags?.includes('1'),
@@ -482,7 +817,7 @@ export default class CustomElement extends ICustomElement {
482
817
  typeof listenerOptions === 'function'
483
818
  ? { handleEvent: listenerOptions }
484
819
  : (typeof listenerOptions === 'string'
485
- ? { prop: listenerOptions }
820
+ ? { prop, deepProp }
486
821
  : listenerOptions)
487
822
  ),
488
823
  ...(
@@ -498,11 +833,23 @@ export default class CustomElement extends ICustomElement {
498
833
  return this;
499
834
  }
500
835
 
501
- /** @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
+ */
502
848
  static childEvents(listenerMap, options) {
503
- for (const [id, listeners] of Object.entries(listenerMap)) {
849
+ for (const [tag, listeners] of Object.entries(listenerMap)) {
850
+ // @ts-expect-error Can't cast T
504
851
  this.events(listeners, {
505
- id,
852
+ tag: attrNameFromPropName(tag),
506
853
  ...options,
507
854
  });
508
855
  }
@@ -511,7 +858,26 @@ export default class CustomElement extends ICustomElement {
511
858
  return this;
512
859
  }
513
860
 
514
- /** @type {typeof ICustomElement['on']} */
861
+ /** @type {typeof CustomElement['events']} */
862
+ static rootEvents(listeners, options) {
863
+ // @ts-expect-error Can't cast T
864
+ return this.events(listeners, {
865
+ tag: Composition.shadowRootTag,
866
+ ...options,
867
+ });
868
+ }
869
+
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
+ */
515
881
  static on(nameOrCallbacks, callback) {
516
882
  const callbacks = typeof nameOrCallbacks === 'string'
517
883
  ? { [nameOrCallbacks]: callback }
@@ -545,31 +911,69 @@ export default class CustomElement extends ICustomElement {
545
911
  return this;
546
912
  }
547
913
 
548
- /** @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
+ */
549
934
  static onPropChanged(options) {
550
- for (const [prop, callback] of Object.entries(options)) {
551
- let array = this.propChangedCallbacks.get(prop);
552
- if (!array) {
553
- array = [];
554
- this.propChangedCallbacks.set(prop, array);
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);
940
+ } else {
941
+ propChangedCallbacks.set(prop, [callback]);
555
942
  }
556
- array.push(callback);
557
943
  }
558
944
 
559
945
  // @ts-expect-error Can't cast T
560
946
  return this;
561
947
  }
562
948
 
563
- /** @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
+ */
564
968
  static onAttributeChanged(options) {
565
- for (const [name, callback] of Object.entries(options)) {
566
- const lcName = name.toLowerCase();
567
- let array = this.attributeChangedCallbacks.get(lcName);
568
- if (!array) {
569
- array = [];
570
- this.attributeChangedCallbacks.set(lcName, array);
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);
974
+ } else {
975
+ attributeChangedCallbacks.set(name, [callback]);
571
976
  }
572
- array.push(callback);
573
977
  }
574
978
 
575
979
  // @ts-expect-error Can't cast T
@@ -588,10 +992,10 @@ export default class CustomElement extends ICustomElement {
588
992
  /** @type {Composition<?>} */
589
993
  #composition;
590
994
 
591
- /** @type {Map<string,null|[string,any]>} */
995
+ /** @type {Map<string,{stringValue:string, parsedValue:any}>} */
592
996
  _propAttributeCache;
593
997
 
594
- /** @type {import('./ICustomElement.js').CallbackArguments} */
998
+ /** @type {CallbackArguments} */
595
999
  _callbackArguments = null;
596
1000
 
597
1001
  /** @param {any[]} args */
@@ -604,7 +1008,24 @@ export default class CustomElement extends ICustomElement {
604
1008
 
605
1009
  this.attachShadow({ mode: 'open', delegatesFocus: this.delegatesFocus });
606
1010
 
607
- this.composition.initialRender(this.shadowRoot, this);
1011
+ /**
1012
+ * Updates nodes based on data
1013
+ * Expects data in JSON Merge Patch format
1014
+ * @see https://www.rfc-editor.org/rfc/rfc7386
1015
+ * @param {Partial<?>} changes
1016
+ * @param {any} data
1017
+ * @return {void}
1018
+ */
1019
+ this.render = this.composition.render(
1020
+ this.constructor.prototype,
1021
+ this,
1022
+ {
1023
+ defaults: this.constructor.prototype,
1024
+ store: this,
1025
+ shadowRoot: this.shadowRoot,
1026
+ context: this,
1027
+ },
1028
+ );
608
1029
 
609
1030
  for (const callback of this.static._onConstructedCallbacks) {
610
1031
  callback.call(this, this.callbackArguments);
@@ -612,25 +1033,26 @@ export default class CustomElement extends ICustomElement {
612
1033
  }
613
1034
 
614
1035
  /**
615
- * Updates nodes based on data
616
- * Expects data in JSON Merge Patch format
617
- * @see https://www.rfc-editor.org/rfc/rfc7386
618
- * @param {?} data
619
- * @param {?} [store]
620
- * @return {void}
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
+ * }}
621
1046
  */
622
- render(data, store) {
623
- // console.log('render', data);
624
- this.composition.render(this.shadowRoot, data, this, store ? { ...this, store } : this);
625
- }
626
-
627
- /** @type {InstanceType<typeof ICustomElement>['propChangedCallback']} */
628
1047
  propChangedCallback(name, oldValue, newValue, changes = newValue) {
629
- this.render({ [name]: changes });
1048
+ if (!this.patching) {
1049
+ this.render.byProp(name, changes, this);
1050
+ // this.render({ [name]: changes });
1051
+ }
630
1052
 
631
- const callbacks = this.static.propChangedCallbacks.get(name);
632
- if (callbacks) {
633
- for (const callback of callbacks) {
1053
+ const { _propChangedCallbacks } = this.static;
1054
+ if (_propChangedCallbacks.has(name)) {
1055
+ for (const callback of _propChangedCallbacks.get(name)) {
634
1056
  callback.call(this, oldValue, newValue, changes, this);
635
1057
  }
636
1058
  }
@@ -642,48 +1064,53 @@ export default class CustomElement extends ICustomElement {
642
1064
  * @param {string|null} newValue
643
1065
  */
644
1066
  attributeChangedCallback(name, oldValue, newValue) {
645
- const callbacks = this.static.attributeChangedCallbacks.get(name.toLowerCase());
646
- if (callbacks) {
647
- for (const callback of callbacks) {
1067
+ const { attributeChangedCallbacks } = this.static;
1068
+ if (attributeChangedCallbacks.has(name)) {
1069
+ for (const callback of attributeChangedCallbacks.get(name)) {
648
1070
  callback.call(this, oldValue, newValue, this);
649
1071
  }
650
1072
  }
651
1073
 
652
1074
  // Array.find
653
- for (const config of this.static.propList.values()) {
654
- if (config.attr !== name) continue;
1075
+ const { attrList } = this.static;
1076
+ if (!attrList.has(name)) return;
655
1077
 
656
- if (config.reflect !== true && config.reflect !== 'read') return;
1078
+ const config = attrList.get(name);
657
1079
 
658
- if (config.attributeChangedCallback) {
659
- config.attributeChangedCallback.call(this, name, oldValue, newValue);
660
- return;
661
- }
1080
+ if (config.attributeChangedCallback) {
1081
+ config.attributeChangedCallback.call(this, name, oldValue, newValue);
1082
+ return;
1083
+ }
662
1084
 
663
- const [stringValue] = this.attributeCache.get(name) ?? [null, null];
664
- if (stringValue === newValue) {
665
- // Attribute was changed via data change event. Ignore.
666
- return;
667
- }
1085
+ let cacheEntry;
1086
+ if (this.attributeCache.has(name)) {
1087
+ cacheEntry = this.attributeCache.get(name);
1088
+ if (cacheEntry.stringValue === newValue) return;
1089
+ }
668
1090
 
669
- // @ts-expect-error any
670
- const previousDataValue = this[config.key];
671
- const parsedValue = newValue === null
672
- ? config.nullParser(/** @type {null} */ (newValue))
673
- // Avoid Boolean('') === false
674
- : (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));
675
1097
 
676
- if (parsedValue === previousDataValue) {
677
- // No internal value change
678
- return;
679
- }
680
- // "Remember" that this attrValue equates to this data value
681
- // Avoids rewriting attribute later on data change event
682
- this.attributeCache.set(name, [newValue, parsedValue]);
683
- // @ts-expect-error any
684
- this[config.key] = parsedValue;
1098
+ if (parsedValue === previousDataValue) {
1099
+ // No internal value change
685
1100
  return;
686
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;
687
1114
  }
688
1115
 
689
1116
  get #template() {
@@ -697,19 +1124,33 @@ export default class CustomElement extends ICustomElement {
697
1124
  * @param {any} changes
698
1125
  */
699
1126
  _onObserverPropertyChanged(name, oldValue, newValue, changes) {
700
- const { reflect, attr } = this.static.propList.get(name);
701
- if (attr && (reflect === true || reflect === 'write')) {
702
- const [, dataValue] = this.attributeCache.get(attr) ?? [null, null];
703
- // Don't change attribute if data value is equivalent
704
- // (eg: Boolean('foo') === true; Number("1.0") === 1)
705
- if (dataValue !== newValue) {
706
- const attrValue = attrValueFromDataValue(newValue);
707
- // Cache attrValue to ignore attributeChangedCallback later
708
- this.attributeCache.set(attr, [attrValue, newValue]);
709
- if (attrValue == null) {
710
- this.removeAttribute(attr);
1127
+ const { propList } = this.static;
1128
+ if (propList.has(name)) {
1129
+ const { reflect, attr } = propList.get(name);
1130
+ if (attr && (reflect === true || reflect === 'write')) {
1131
+ /** @type {{stringValue:string, parsedValue:any}} */
1132
+ let cacheEntry;
1133
+ let needsWrite = false;
1134
+ const { attributeCache } = this;
1135
+ if (attributeCache.has(attr)) {
1136
+ cacheEntry = attributeCache.get(attr);
1137
+ needsWrite = (cacheEntry.parsedValue !== newValue);
711
1138
  } else {
712
- this.setAttribute(attr, attrValue);
1139
+ // @ts-ignore skip cast
1140
+ cacheEntry = {};
1141
+ attributeCache.set(attr, cacheEntry);
1142
+ needsWrite = true;
1143
+ }
1144
+ if (needsWrite) {
1145
+ const stringValue = attrValueFromDataValue(newValue);
1146
+ cacheEntry.parsedValue = newValue;
1147
+ cacheEntry.stringValue = stringValue;
1148
+ // Cache attrValue to ignore attributeChangedCallback later
1149
+ if (stringValue == null) {
1150
+ this.removeAttribute(attr);
1151
+ } else {
1152
+ this.setAttribute(attr, stringValue);
1153
+ }
713
1154
  }
714
1155
  }
715
1156
  }
@@ -718,8 +1159,15 @@ export default class CustomElement extends ICustomElement {
718
1159
  this.propChangedCallback(name, oldValue, newValue, changes);
719
1160
  }
720
1161
 
1162
+ patch(patch) {
1163
+ this.patching = true;
1164
+ applyMergePatch(this, patch);
1165
+ this.render(patch);
1166
+ this.patching = false;
1167
+ }
1168
+
721
1169
  /**
722
- * Proxy object that returns shadow DOM elements by ID.
1170
+ * Proxy object that returns shadow DOM elements by tag.
723
1171
  * If called before interpolation (eg: on composed), returns from template
724
1172
  * @return {Record<string,HTMLElement>}
725
1173
  */
@@ -728,82 +1176,48 @@ export default class CustomElement extends ICustomElement {
728
1176
  return (this.#refsProxy ??= new Proxy({}, {
729
1177
  /**
730
1178
  * @param {any} target
731
- * @param {string} id
1179
+ * @param {string} tag
732
1180
  * @return {Element}
733
1181
  */
734
- get: (target, id) => {
1182
+ get: (target, tag) => {
735
1183
  if (!this.#composition) {
736
1184
  console.warn(this.static.name, 'Attempted to access references before composing!');
737
1185
  }
738
1186
  const composition = this.composition;
1187
+ let element;
739
1188
  if (!composition.interpolated) {
740
- let element = this.#refsCompositionCache.get(id)?.deref();
741
- if (element) return element;
742
- const formattedId = attrNameFromPropName(id);
1189
+ if (this.#refsCompositionCache.has(tag)) {
1190
+ element = this.#refsCompositionCache.get(tag).deref();
1191
+ if (element) return element;
1192
+ }
1193
+ const formattedTag = attrNameFromPropName(tag);
743
1194
  // console.warn(this.tagName, 'Returning template reference');
744
- element = composition.template.getElementById(formattedId);
1195
+ element = composition.template.getElementById(formattedTag);
745
1196
  if (!element) return null;
746
- this.#refsCompositionCache.set(id, new WeakRef(element));
1197
+ this.#refsCompositionCache.set(tag, new WeakRef(element));
747
1198
  return element;
748
1199
  }
749
- let element = this.#refsCache.get(id)?.deref();
750
- if (element) {
751
- return element;
1200
+ if (this.#refsCache.has(tag)) {
1201
+ element = this.#refsCache.get(tag).deref();
1202
+ if (element) {
1203
+ return element;
1204
+ }
752
1205
  }
753
- const formattedId = attrNameFromPropName(id);
754
- element = composition.getElement(this.shadowRoot, formattedId);
1206
+
1207
+ const formattedTag = attrNameFromPropName(tag);
1208
+ const tagIndex = this.composition.tags.indexOf(formattedTag);
1209
+ element = this.render.state.refs[tagIndex];
1210
+
755
1211
  if (!element) return null;
756
- this.#refsCache.set(id, new WeakRef(element));
1212
+ this.#refsCache.set(tag, new WeakRef(element));
757
1213
  return element;
758
1214
  },
759
1215
  }));
760
1216
  }
761
1217
 
762
1218
  get attributeCache() {
763
- this._propAttributeCache ??= new Map();
764
- return this._propAttributeCache;
765
- }
766
-
767
- get tabIndex() {
768
- return super.tabIndex;
769
- }
770
-
771
- set tabIndex(value) {
772
- if (value === super.tabIndex && value !== -1) {
773
- // Non -1 value already set
774
- return;
775
- }
776
-
777
- if (this.delegatesFocus && document.activeElement === this) {
778
- if (this.getAttribute('tabindex') === value.toString()) {
779
- // Skip if possible
780
- return;
781
- }
782
-
783
- // Chrome blurs on tabindex changes with delegatesFocus
784
- // Fixed in Chrome 111
785
- // Remove this code ~June 2023
786
- // https://bugs.chromium.org/p/chromium/issues/detail?id=1346606
787
- /** @type {EventListener} */
788
- const listener = (e) => {
789
- e.stopImmediatePropagation();
790
- e.stopPropagation();
791
- if (e.type === 'blur') {
792
- console.warn('Chromium bug 1346606: Tabindex change caused blur. Giving focusing back.', this);
793
- this.focus();
794
- } else {
795
- console.warn('Chromium bug 1346606: Blocking focus event.', this);
796
- }
797
- };
798
- this.addEventListener('blur', listener, { capture: true, once: true });
799
- this.addEventListener('focus', listener, { capture: true, once: true });
800
- super.tabIndex = value;
801
- this.removeEventListener('blur', listener, { capture: true });
802
- this.removeEventListener('focus', listener, { capture: true });
803
- return;
804
- }
805
-
806
- super.tabIndex = value;
1219
+ // eslint-disable-next-line no-return-assign
1220
+ return (this._propAttributeCache ??= new Map());
807
1221
  }
808
1222
 
809
1223
  get static() { return /** @type {typeof CustomElement} */ (/** @type {unknown} */ (this.constructor)); }
@@ -814,6 +1228,7 @@ export default class CustomElement extends ICustomElement {
814
1228
  // eslint-disable-next-line no-return-assign
815
1229
  return this._callbackArguments ??= {
816
1230
  composition: this.#composition,
1231
+ refs: this.refs,
817
1232
  html: html.bind(this),
818
1233
  inline: addInlineFunction,
819
1234
  template: this.#template,