@shortfuse/materialdesignweb 0.8.0 → 0.9.1

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 (405) hide show
  1. package/README.md +50 -198
  2. package/bin/mdw-css.js +1 -1
  3. package/components/Badge.js +15 -5
  4. package/components/Body.js +7 -0
  5. package/components/BottomAppBar.js +7 -10
  6. package/components/BottomSheet.js +472 -0
  7. package/components/Box.js +11 -49
  8. package/components/Button.js +81 -82
  9. package/components/Card.js +74 -62
  10. package/components/Checkbox.js +15 -25
  11. package/components/CheckboxIcon.js +19 -31
  12. package/components/Chip.js +18 -13
  13. package/components/Dialog.js +70 -100
  14. package/components/DialogActions.js +4 -0
  15. package/components/Display.js +64 -0
  16. package/components/Divider.js +5 -0
  17. package/components/Fab.js +94 -17
  18. package/components/FabContainer.js +57 -0
  19. package/components/FilterChip.js +43 -32
  20. package/components/Grid.js +187 -0
  21. package/components/Headline.js +9 -28
  22. package/components/Icon.js +80 -71
  23. package/components/IconButton.js +77 -120
  24. package/components/Input.js +745 -86
  25. package/components/InputChip.js +193 -0
  26. package/components/Label.js +7 -0
  27. package/components/List.js +11 -5
  28. package/components/ListItem.js +92 -23
  29. package/components/ListOption.js +143 -65
  30. package/components/Listbox.js +57 -17
  31. package/components/Menu.js +39 -27
  32. package/components/MenuItem.js +49 -36
  33. package/components/NavBar.js +66 -21
  34. package/components/NavBarItem.js +5 -0
  35. package/components/NavDrawer.js +33 -16
  36. package/components/NavDrawerItem.js +7 -4
  37. package/components/NavItem.js +61 -34
  38. package/components/NavRail.js +32 -21
  39. package/components/NavRailItem.js +10 -2
  40. package/components/Page.js +119 -0
  41. package/components/Pane.js +24 -0
  42. package/components/Popup.js +23 -8
  43. package/components/Progress.js +25 -5
  44. package/components/Radio.js +8 -7
  45. package/components/RadioIcon.js +24 -15
  46. package/components/Ripple.js +25 -7
  47. package/components/Root.js +225 -0
  48. package/components/Scrim.js +95 -0
  49. package/components/Search.js +30 -25
  50. package/components/SegmentedButton.js +53 -40
  51. package/components/SegmentedButtonGroup.js +15 -12
  52. package/components/Select.js +19 -10
  53. package/components/Shape.js +10 -66
  54. package/components/SideSheet.js +337 -0
  55. package/components/Slider.js +93 -36
  56. package/components/Snackbar.js +52 -20
  57. package/components/SnackbarContainer.js +51 -0
  58. package/components/Surface.js +20 -10
  59. package/components/Switch.js +21 -18
  60. package/components/SwitchIcon.js +62 -33
  61. package/components/Tab.js +78 -38
  62. package/components/TabContent.js +33 -12
  63. package/components/TabList.js +95 -34
  64. package/components/TabPanel.js +10 -1
  65. package/components/Table.js +151 -0
  66. package/components/TextArea.js +48 -16
  67. package/components/Title.js +8 -9
  68. package/components/Tooltip.js +51 -22
  69. package/components/TopAppBar.js +71 -78
  70. package/constants/shapes.js +36 -0
  71. package/constants/typography.js +127 -0
  72. package/core/Composition.js +391 -201
  73. package/core/CompositionAdapter.js +35 -18
  74. package/core/CustomElement.js +634 -254
  75. package/core/css.js +117 -12
  76. package/core/customTypes.js +161 -49
  77. package/core/dom.js +18 -11
  78. package/core/jsonMergePatch.js +27 -11
  79. package/core/observe.js +308 -256
  80. package/core/optimizations.js +9 -9
  81. package/core/template.js +14 -57
  82. package/dist/CustomElement.min.js +2 -0
  83. package/dist/CustomElement.min.js.map +7 -0
  84. package/dist/core/CustomElement.min.js +2 -0
  85. package/dist/core/CustomElement.min.js.map +7 -0
  86. package/dist/index.min.js +85 -115
  87. package/dist/index.min.js.map +4 -4
  88. package/dist/meta.json +1 -1
  89. package/dom/HTMLOptionsCollectionProxy.js +108 -0
  90. package/{theming/themableMixinLoader.js → loaders/palette.js} +4 -3
  91. package/loaders/theme.js +12 -0
  92. package/mixins/AriaReflectorMixin.js +64 -15
  93. package/mixins/AriaToolbarMixin.js +6 -0
  94. package/mixins/ControlMixin.js +79 -33
  95. package/mixins/DelegatesFocusMixin.js +62 -0
  96. package/mixins/DensityMixin.js +7 -3
  97. package/mixins/ElevationMixin.js +61 -0
  98. package/mixins/FlexableMixin.js +87 -39
  99. package/mixins/FormAssociatedMixin.js +76 -10
  100. package/mixins/HyperlinkMixin.js +76 -0
  101. package/mixins/InputMixin.js +227 -32
  102. package/mixins/KeyboardNavMixin.js +11 -7
  103. package/mixins/NavigationListenerMixin.js +33 -0
  104. package/mixins/PopupMixin.js +216 -219
  105. package/mixins/RTLObserverMixin.js +2 -0
  106. package/mixins/ResizeObserverMixin.js +18 -4
  107. package/mixins/RippleMixin.js +11 -7
  108. package/mixins/ScrollListenerMixin.js +14 -2
  109. package/mixins/SemiStickyMixin.js +51 -98
  110. package/mixins/ShapeMaskedMixin.js +125 -0
  111. package/mixins/ShapeMixin.js +30 -203
  112. package/mixins/StateMixin.js +74 -34
  113. package/mixins/TextFieldMixin.js +128 -145
  114. package/mixins/ThemableMixin.js +57 -56
  115. package/mixins/TooltipTriggerMixin.js +305 -359
  116. package/mixins/TouchTargetMixin.js +5 -2
  117. package/mixins/TypographyMixin.js +128 -0
  118. package/package.json +125 -81
  119. package/services/rtl.js +10 -0
  120. package/services/svgAlias.js +17 -0
  121. package/{theming/index.js → services/theme.js} +25 -176
  122. package/types/bin/mdw-css.d.ts +3 -0
  123. package/types/bin/mdw-css.d.ts.map +1 -0
  124. package/types/components/Badge.d.ts +39 -0
  125. package/types/components/Badge.d.ts.map +1 -0
  126. package/types/components/Body.d.ts +29 -0
  127. package/types/components/Body.d.ts.map +1 -0
  128. package/types/components/BottomAppBar.d.ts +72 -0
  129. package/types/components/BottomAppBar.d.ts.map +1 -0
  130. package/types/components/BottomSheet.d.ts +135 -0
  131. package/types/components/BottomSheet.d.ts.map +1 -0
  132. package/types/components/Box.d.ts +16 -0
  133. package/types/components/Box.d.ts.map +1 -0
  134. package/types/components/Button.d.ts +245 -0
  135. package/types/components/Button.d.ts.map +1 -0
  136. package/types/components/Card.d.ts +147 -0
  137. package/types/components/Card.d.ts.map +1 -0
  138. package/types/components/Checkbox.d.ts +207 -0
  139. package/types/components/Checkbox.d.ts.map +1 -0
  140. package/types/components/CheckboxIcon.d.ts +44 -0
  141. package/types/components/CheckboxIcon.d.ts.map +1 -0
  142. package/types/components/Chip.d.ts +248 -0
  143. package/types/components/Chip.d.ts.map +1 -0
  144. package/types/components/Dialog.d.ts +103 -0
  145. package/types/components/Dialog.d.ts.map +1 -0
  146. package/types/components/DialogActions.d.ts +4 -0
  147. package/types/components/DialogActions.d.ts.map +1 -0
  148. package/types/components/Display.d.ts +46 -0
  149. package/types/components/Display.d.ts.map +1 -0
  150. package/types/components/Divider.d.ts +10 -0
  151. package/types/components/Divider.d.ts.map +1 -0
  152. package/types/components/Fab.d.ts +273 -0
  153. package/types/components/Fab.d.ts.map +1 -0
  154. package/types/components/FabContainer.d.ts +10 -0
  155. package/types/components/FabContainer.d.ts.map +1 -0
  156. package/types/components/FilterChip.d.ts +256 -0
  157. package/types/components/FilterChip.d.ts.map +1 -0
  158. package/types/components/Grid.d.ts +38 -0
  159. package/types/components/Grid.d.ts.map +1 -0
  160. package/types/components/Headline.d.ts +46 -0
  161. package/types/components/Headline.d.ts.map +1 -0
  162. package/types/components/Icon.d.ts +55 -0
  163. package/types/components/Icon.d.ts.map +1 -0
  164. package/types/components/IconButton.d.ts +284 -0
  165. package/types/components/IconButton.d.ts.map +1 -0
  166. package/types/components/Input.d.ts +2528 -0
  167. package/types/components/Input.d.ts.map +1 -0
  168. package/types/components/InputChip.d.ts +85 -0
  169. package/types/components/InputChip.d.ts.map +1 -0
  170. package/types/components/Label.d.ts +29 -0
  171. package/types/components/Label.d.ts.map +1 -0
  172. package/types/components/List.d.ts +35 -0
  173. package/types/components/List.d.ts.map +1 -0
  174. package/types/components/ListItem.d.ts +124 -0
  175. package/types/components/ListItem.d.ts.map +1 -0
  176. package/types/components/ListOption.d.ts +158 -0
  177. package/types/components/ListOption.d.ts.map +1 -0
  178. package/types/components/Listbox.d.ts +763 -0
  179. package/types/components/Listbox.d.ts.map +1 -0
  180. package/types/components/Menu.d.ts +130 -0
  181. package/types/components/Menu.d.ts.map +1 -0
  182. package/types/components/MenuItem.d.ts +232 -0
  183. package/types/components/MenuItem.d.ts.map +1 -0
  184. package/types/components/NavBar.d.ts +20 -0
  185. package/types/components/NavBar.d.ts.map +1 -0
  186. package/types/components/NavBarItem.d.ts +97 -0
  187. package/types/components/NavBarItem.d.ts.map +1 -0
  188. package/types/components/NavDrawer.d.ts +107 -0
  189. package/types/components/NavDrawer.d.ts.map +1 -0
  190. package/types/components/NavDrawerItem.d.ts +97 -0
  191. package/types/components/NavDrawerItem.d.ts.map +1 -0
  192. package/types/components/NavItem.d.ts +99 -0
  193. package/types/components/NavItem.d.ts.map +1 -0
  194. package/types/components/NavRail.d.ts +108 -0
  195. package/types/components/NavRail.d.ts.map +1 -0
  196. package/types/components/NavRailItem.d.ts +97 -0
  197. package/types/components/NavRailItem.d.ts.map +1 -0
  198. package/types/components/Page.d.ts +25 -0
  199. package/types/components/Page.d.ts.map +1 -0
  200. package/types/components/Pane.d.ts +44 -0
  201. package/types/components/Pane.d.ts.map +1 -0
  202. package/types/components/Popup.d.ts +78 -0
  203. package/types/components/Popup.d.ts.map +1 -0
  204. package/types/components/Progress.d.ts +21 -0
  205. package/types/components/Progress.d.ts.map +1 -0
  206. package/types/components/Radio.d.ts +201 -0
  207. package/types/components/Radio.d.ts.map +1 -0
  208. package/types/components/RadioIcon.d.ts +46 -0
  209. package/types/components/RadioIcon.d.ts.map +1 -0
  210. package/types/components/Ripple.d.ts +35 -0
  211. package/types/components/Ripple.d.ts.map +1 -0
  212. package/types/components/Root.d.ts +68 -0
  213. package/types/components/Root.d.ts.map +1 -0
  214. package/types/components/Scrim.d.ts +6 -0
  215. package/types/components/Scrim.d.ts.map +1 -0
  216. package/types/components/Search.d.ts +516 -0
  217. package/types/components/Search.d.ts.map +1 -0
  218. package/types/components/SegmentedButton.d.ts +252 -0
  219. package/types/components/SegmentedButton.d.ts.map +1 -0
  220. package/types/components/SegmentedButtonGroup.d.ts +43 -0
  221. package/types/components/SegmentedButtonGroup.d.ts.map +1 -0
  222. package/types/components/Select.d.ts +158 -0
  223. package/types/components/Select.d.ts.map +1 -0
  224. package/types/components/Shape.d.ts +10 -0
  225. package/types/components/Shape.d.ts.map +1 -0
  226. package/types/components/SideSheet.d.ts +111 -0
  227. package/types/components/SideSheet.d.ts.map +1 -0
  228. package/types/components/Slider.d.ts +203 -0
  229. package/types/components/Slider.d.ts.map +1 -0
  230. package/types/components/Snackbar.d.ts +73 -0
  231. package/types/components/Snackbar.d.ts.map +1 -0
  232. package/types/components/SnackbarContainer.d.ts +6 -0
  233. package/types/components/SnackbarContainer.d.ts.map +1 -0
  234. package/types/components/Surface.d.ts +45 -0
  235. package/types/components/Surface.d.ts.map +1 -0
  236. package/types/components/Switch.d.ts +187 -0
  237. package/types/components/Switch.d.ts.map +1 -0
  238. package/types/components/SwitchIcon.d.ts +61 -0
  239. package/types/components/SwitchIcon.d.ts.map +1 -0
  240. package/types/components/Tab.d.ts +139 -0
  241. package/types/components/Tab.d.ts.map +1 -0
  242. package/types/components/TabContent.d.ts +124 -0
  243. package/types/components/TabContent.d.ts.map +1 -0
  244. package/types/components/TabList.d.ts +1111 -0
  245. package/types/components/TabList.d.ts.map +1 -0
  246. package/types/components/TabPanel.d.ts +28 -0
  247. package/types/components/TabPanel.d.ts.map +1 -0
  248. package/types/components/Table.d.ts +25 -0
  249. package/types/components/Table.d.ts.map +1 -0
  250. package/types/components/TextArea.d.ts +201 -0
  251. package/types/components/TextArea.d.ts.map +1 -0
  252. package/types/components/Title.d.ts +46 -0
  253. package/types/components/Title.d.ts.map +1 -0
  254. package/types/components/Tooltip.d.ts +49 -0
  255. package/types/components/Tooltip.d.ts.map +1 -0
  256. package/types/components/TopAppBar.d.ts +129 -0
  257. package/types/components/TopAppBar.d.ts.map +1 -0
  258. package/types/constants/colorKeywords.d.ts +2 -0
  259. package/types/constants/colorKeywords.d.ts.map +1 -0
  260. package/types/constants/shapes.d.ts +38 -0
  261. package/types/constants/shapes.d.ts.map +1 -0
  262. package/types/constants/typography.d.ts +212 -0
  263. package/types/constants/typography.d.ts.map +1 -0
  264. package/types/core/Composition.d.ts +260 -0
  265. package/types/core/Composition.d.ts.map +1 -0
  266. package/types/core/CompositionAdapter.d.ts +114 -0
  267. package/types/core/CompositionAdapter.d.ts.map +1 -0
  268. package/types/core/CustomElement.d.ts +304 -0
  269. package/types/core/CustomElement.d.ts.map +1 -0
  270. package/types/core/css.d.ts +44 -0
  271. package/types/core/css.d.ts.map +1 -0
  272. package/types/core/customTypes.d.ts +22 -0
  273. package/types/core/customTypes.d.ts.map +1 -0
  274. package/types/core/dom.d.ts +32 -0
  275. package/types/core/dom.d.ts.map +1 -0
  276. package/types/core/jsonMergePatch.d.ts +31 -0
  277. package/types/core/jsonMergePatch.d.ts.map +1 -0
  278. package/types/core/observe.d.ts +114 -0
  279. package/types/core/observe.d.ts.map +1 -0
  280. package/types/core/optimizations.d.ts +7 -0
  281. package/types/core/optimizations.d.ts.map +1 -0
  282. package/types/core/template.d.ts +47 -0
  283. package/types/core/template.d.ts.map +1 -0
  284. package/types/core/uid.d.ts +6 -0
  285. package/types/core/uid.d.ts.map +1 -0
  286. package/types/dom/HTMLOptionsCollectionProxy.d.ts +18 -0
  287. package/types/dom/HTMLOptionsCollectionProxy.d.ts.map +1 -0
  288. package/types/index.d.ts +88 -0
  289. package/types/index.d.ts.map +1 -0
  290. package/types/loaders/palette.d.ts +2 -0
  291. package/types/loaders/palette.d.ts.map +1 -0
  292. package/types/loaders/theme.d.ts +2 -0
  293. package/types/loaders/theme.d.ts.map +1 -0
  294. package/types/mixins/AriaReflectorMixin.d.ts +31 -0
  295. package/types/mixins/AriaReflectorMixin.d.ts.map +1 -0
  296. package/types/mixins/AriaToolbarMixin.d.ts +34 -0
  297. package/types/mixins/AriaToolbarMixin.d.ts.map +1 -0
  298. package/types/mixins/ControlMixin.d.ts +124 -0
  299. package/types/mixins/ControlMixin.d.ts.map +1 -0
  300. package/types/mixins/DelegatesFocusMixin.d.ts +13 -0
  301. package/types/mixins/DelegatesFocusMixin.d.ts.map +1 -0
  302. package/types/mixins/DensityMixin.d.ts +8 -0
  303. package/types/mixins/DensityMixin.d.ts.map +1 -0
  304. package/types/mixins/ElevationMixin.d.ts +32 -0
  305. package/types/mixins/ElevationMixin.d.ts.map +1 -0
  306. package/types/mixins/FlexableMixin.d.ts +14 -0
  307. package/types/mixins/FlexableMixin.d.ts.map +1 -0
  308. package/types/mixins/FormAssociatedMixin.d.ts +123 -0
  309. package/types/mixins/FormAssociatedMixin.d.ts.map +1 -0
  310. package/types/mixins/HyperlinkMixin.d.ts +25 -0
  311. package/types/mixins/HyperlinkMixin.d.ts.map +1 -0
  312. package/types/mixins/InputMixin.d.ts +173 -0
  313. package/types/mixins/InputMixin.d.ts.map +1 -0
  314. package/types/mixins/KeyboardNavMixin.d.ts +46 -0
  315. package/types/mixins/KeyboardNavMixin.d.ts.map +1 -0
  316. package/types/mixins/NavigationListenerMixin.d.ts +8 -0
  317. package/types/mixins/NavigationListenerMixin.d.ts.map +1 -0
  318. package/types/mixins/PopupMixin.d.ts +98 -0
  319. package/types/mixins/PopupMixin.d.ts.map +1 -0
  320. package/types/mixins/RTLObserverMixin.d.ts +8 -0
  321. package/types/mixins/RTLObserverMixin.d.ts.map +1 -0
  322. package/types/mixins/ResizeObserverMixin.d.ts +13 -0
  323. package/types/mixins/ResizeObserverMixin.d.ts.map +1 -0
  324. package/types/mixins/RippleMixin.d.ts +94 -0
  325. package/types/mixins/RippleMixin.d.ts.map +1 -0
  326. package/types/mixins/ScrollListenerMixin.d.ts +46 -0
  327. package/types/mixins/ScrollListenerMixin.d.ts.map +1 -0
  328. package/types/mixins/SemiStickyMixin.d.ts +50 -0
  329. package/types/mixins/SemiStickyMixin.d.ts.map +1 -0
  330. package/types/mixins/ShapeMaskedMixin.d.ts +12 -0
  331. package/types/mixins/ShapeMaskedMixin.d.ts.map +1 -0
  332. package/types/mixins/ShapeMixin.d.ts +39 -0
  333. package/types/mixins/ShapeMixin.d.ts.map +1 -0
  334. package/types/mixins/StateMixin.d.ts +29 -0
  335. package/types/mixins/StateMixin.d.ts.map +1 -0
  336. package/types/mixins/TextFieldMixin.d.ts +153 -0
  337. package/types/mixins/TextFieldMixin.d.ts.map +1 -0
  338. package/types/mixins/ThemableMixin.d.ts +10 -0
  339. package/types/mixins/ThemableMixin.d.ts.map +1 -0
  340. package/types/mixins/TooltipTriggerMixin.d.ts +114 -0
  341. package/types/mixins/TooltipTriggerMixin.d.ts.map +1 -0
  342. package/types/mixins/TouchTargetMixin.d.ts +6 -0
  343. package/types/mixins/TouchTargetMixin.d.ts.map +1 -0
  344. package/types/mixins/TypographyMixin.d.ts +20 -0
  345. package/types/mixins/TypographyMixin.d.ts.map +1 -0
  346. package/types/services/rtl.d.ts +3 -0
  347. package/types/services/rtl.d.ts.map +1 -0
  348. package/types/services/svgAlias.d.ts +13 -0
  349. package/types/services/svgAlias.d.ts.map +1 -0
  350. package/types/services/theme.d.ts +45 -0
  351. package/types/services/theme.d.ts.map +1 -0
  352. package/types/utils/cli.d.ts +3 -0
  353. package/types/utils/cli.d.ts.map +1 -0
  354. package/types/utils/function.d.ts +3 -0
  355. package/types/utils/function.d.ts.map +1 -0
  356. package/types/utils/jsx-runtime.d.ts +20 -0
  357. package/types/utils/jsx-runtime.d.ts.map +1 -0
  358. package/types/utils/material-color/blend.d.ts +34 -0
  359. package/types/utils/material-color/blend.d.ts.map +1 -0
  360. package/types/utils/material-color/hct/Cam16.d.ts +142 -0
  361. package/types/utils/material-color/hct/Cam16.d.ts.map +1 -0
  362. package/types/utils/material-color/hct/Hct.d.ts +93 -0
  363. package/types/utils/material-color/hct/Hct.d.ts.map +1 -0
  364. package/types/utils/material-color/hct/ViewingConditions.d.ts +69 -0
  365. package/types/utils/material-color/hct/ViewingConditions.d.ts.map +1 -0
  366. package/types/utils/material-color/hct/hctSolver.d.ts +30 -0
  367. package/types/utils/material-color/hct/hctSolver.d.ts.map +1 -0
  368. package/types/utils/material-color/helper.d.ts +8 -0
  369. package/types/utils/material-color/helper.d.ts.map +1 -0
  370. package/types/utils/material-color/palettes/CorePalette.d.ts +75 -0
  371. package/types/utils/material-color/palettes/CorePalette.d.ts.map +1 -0
  372. package/types/utils/material-color/palettes/TonalPalette.d.ts +38 -0
  373. package/types/utils/material-color/palettes/TonalPalette.d.ts.map +1 -0
  374. package/types/utils/material-color/scheme/Scheme.d.ts +264 -0
  375. package/types/utils/material-color/scheme/Scheme.d.ts.map +1 -0
  376. package/types/utils/material-color/utils/color.d.ts +172 -0
  377. package/types/utils/material-color/utils/color.d.ts.map +1 -0
  378. package/types/utils/material-color/utils/math.d.ts +94 -0
  379. package/types/utils/material-color/utils/math.d.ts.map +1 -0
  380. package/types/utils/pixelmatch.d.ts +22 -0
  381. package/types/utils/pixelmatch.d.ts.map +1 -0
  382. package/types/utils/popup.d.ts +106 -0
  383. package/types/utils/popup.d.ts.map +1 -0
  384. package/types/utils/searchParams.d.ts +3 -0
  385. package/types/utils/searchParams.d.ts.map +1 -0
  386. package/types/utils/svg.d.ts +7 -0
  387. package/types/utils/svg.d.ts.map +1 -0
  388. package/utils/jsx-runtime.js +9 -4
  389. package/utils/material-color/scheme/Scheme.js +1 -1
  390. package/utils/pixelmatch.js +363 -0
  391. package/utils/popup.js +86 -10
  392. package/utils/searchParams.js +22 -0
  393. package/components/Button.md +0 -61
  394. package/components/ExtendedFab.js +0 -32
  395. package/components/Layout.js +0 -504
  396. package/components/Nav.js +0 -38
  397. package/core/DomAdapter.js +0 -586
  398. package/core/ICustomElement.d.ts +0 -291
  399. package/core/ICustomElement.js +0 -1
  400. package/core/test.js +0 -126
  401. package/core/typings.d.ts +0 -142
  402. package/core/typings.js +0 -1
  403. package/mixins/SurfaceMixin.js +0 -127
  404. package/theming/loader.js +0 -22
  405. /package/{utils/color_keywords.js → constants/colorKeywords.js} +0 -0
package/core/observe.js CHANGED
@@ -1,65 +1,63 @@
1
1
  import { attrNameFromPropName } from './dom.js';
2
2
  import { buildMergePatch, hasMergePatch } from './jsonMergePatch.js';
3
3
 
4
- /** @typedef {import('./typings.js').ObserverPropertyType} ObserverPropertyType */
5
-
6
- /** @return {null} */
7
- const DEFAULT_NULL_PARSER = () => null;
4
+ /** @typedef {'string' | 'boolean' | 'map' | 'set' | 'float' | 'integer' | 'object' | 'function' | 'array'} ObserverPropertyType */
8
5
 
9
6
  /**
10
- * @see https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Boolean#boolean_coercion
11
- * @param {any} v
12
- * @return {boolean}
7
+ * @template {ObserverPropertyType} T
8
+ * @typedef {(
9
+ * T extends 'boolean' ? boolean
10
+ * : T extends 'string' ? string
11
+ * : T extends 'float' | 'integer' ? number
12
+ * : T extends 'array' ? any[]
13
+ * : T extends 'object' ? any
14
+ * : T extends 'function' ? (...args:any) => any
15
+ * : unknown
16
+ * )} ParsedObserverPropertyType
13
17
  */
14
- const DEFAULT_BOOLEAN_PARSER = (v) => !!v;
15
18
 
16
19
  /**
17
- * Doesn't support `BigInt` types
18
- * @see https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Number#number_coercion
19
- * @param {any} v
20
- * @return {number}
21
- */
22
- const DEFAULT_NUMBER_PARSER = (v) => +v;
23
-
24
- /**
25
- * Doesn't support `Symbol` types
26
- * @see https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String#string_coercion
27
- * @param {any} v
28
- * @return {string}
29
- */
30
- const DEFAULT_STRING_PARSER = (v) => `${v}`;
31
-
32
- /**
33
- * @template T
34
- * @param {T} o
35
- * @return {T}
36
- */
37
- const DEFAULT_OBJECT_PARSER = (o) => o;
38
-
39
- /**
40
- * @template T
41
- * @param {T} a
42
- * @param {T} b
43
- * @return {boolean} true if equal
44
- */
45
- const DEFAULT_OBJECT_COMPARATOR = (a, b) => !hasMergePatch(a, b);
46
-
47
- /**
48
- * Always invoke change on set
49
- * @template T
50
- * @param {T} a
51
- * @param {T} b
52
- * @return {boolean} true if equal
20
+ * @template {ObserverPropertyType} T1
21
+ * @template {any} T2
22
+ * @template {Object} [C=any]
23
+ * @typedef {Object} ObserverOptions
24
+ * @prop {T1} [type]
25
+ * @prop {boolean} [enumerable]
26
+ * @prop {boolean|'write'|'read'} [reflect]
27
+ * @prop {string} [attr]
28
+ * @prop {boolean} [readonly]
29
+ * Defaults to false if type is boolean
30
+ * @prop {boolean} [nullable]
31
+ * @prop {T2} [empty]
32
+ * @prop {T2} [value]
33
+ * @prop {(this:C, data:Partial<C>, fn?: () => T2) => T2} [get]
34
+ * Function used when null passed
35
+ * @prop {(this:C, value:any)=>T2} [parser]
36
+ * @prop {(this:C, value:null|undefined)=>T2} [nullParser]
37
+ * @prop {(this:C, value: T2, fn?:(value2: T2) => any) => any} [set]
38
+ * Function used when comparing
39
+ * @prop {(this:C, a:T2, b:T2)=> any} [diff]
40
+ * @prop {(this:C, a:T2, b:T2)=>boolean} [is]
41
+ * Simple callback
42
+ * @prop {(this:C, oldValue:T2, newValue:T2, changes:any)=>any} [changedCallback]
43
+ * Named callback
44
+ * @prop {(this:C, name:string, oldValue: T2, newValue: T2, changes:any) => any} [propChangedCallback]
45
+ * Attribute callback
46
+ * @prop {(this:C, name:keyof C & string, oldValue: string, newValue: string) => any} [attributeChangedCallback]
47
+ * @prop {[keyof C & string, (this:C, ...args:any[]) => any][]} [watchers]
48
+ * @prop {Set<keyof C & string>} [props]
49
+ * @prop {WeakMap<C,T2>} [values]
50
+ * @prop {WeakMap<C, T2>} [computedValues]
51
+ * @prop {WeakSet<C>} [needsSelfInvalidation]
53
52
  */
54
- const DEFAULT_ARRAY_COMPARATOR = (a, b) => false;
55
53
 
56
54
  /**
57
- * @template T
58
- * @param {T} a
59
- * @param {T} b
60
- * @return {boolean} true if equal
55
+ * @template {ObserverPropertyType} T1
56
+ * @template {any} [T2=any]
57
+ * @template {Object} [C=any]
58
+ * @template {keyof C & string} [K=any]
59
+ * @typedef {ObserverOptions<T1, T2, C> & { key: K, values?: WeakMap<C, T2>; attrValues?: WeakMap<C, string> }} ObserverConfiguration
61
60
  */
62
- const DEFAULT_OBJECT_DIFF = (a, b) => buildMergePatch(a, b, 'reference');
63
61
 
64
62
  /**
65
63
  * @param {ObserverPropertyType} type
@@ -95,9 +93,11 @@ function emptyFromType(type) {
95
93
  * @return {T}
96
94
  */
97
95
  function buildProxy(proxyTarget, set, deepSet, prefix) {
96
+ // @ts-ignore
98
97
  proxyTarget ??= {};
99
98
  return new Proxy(proxyTarget, {
100
99
  get(target, p) {
100
+ // @ts-ignore
101
101
  const value = target[p];
102
102
  if (typeof p !== 'symbol') {
103
103
  const arg = prefix ? `${prefix}.${p}` : p;
@@ -107,7 +107,6 @@ function buildProxy(proxyTarget, set, deepSet, prefix) {
107
107
  set.add(arg);
108
108
  }
109
109
  if (typeof value === 'object' && value != null) {
110
- console.debug('tried to arg poke object get', p, value);
111
110
  return buildProxy(value, set, deepSet, arg);
112
111
  }
113
112
  }
@@ -135,127 +134,225 @@ function buildProxy(proxyTarget, set, deepSet, prefix) {
135
134
  function defaultParserFromType(type) {
136
135
  switch (type) {
137
136
  case 'boolean':
138
- return DEFAULT_BOOLEAN_PARSER;
137
+ /**
138
+ * @see https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Boolean#boolean_coercion
139
+ * @param {any} v
140
+ * @return {boolean}
141
+ */
142
+ return (v) => !!v;
139
143
  case 'integer':
140
144
  // Calls ToNumber(x)
141
145
  return Math.round;
142
146
  case 'float':
143
- return DEFAULT_NUMBER_PARSER;
147
+ /**
148
+ * Doesn't support `BigInt` types
149
+ * @see https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Number#number_coercion
150
+ * @param {any} v
151
+ * @return {number}
152
+ */
153
+ return (v) => +v;
144
154
  case 'map':
145
155
  return Map;
146
156
  case 'set':
147
157
  return Set;
148
158
  case 'object':
149
- return DEFAULT_OBJECT_PARSER;
150
159
  case 'array':
151
- return DEFAULT_OBJECT_PARSER;
160
+ /**
161
+ * Reflect self
162
+ * @template T
163
+ * @param {T} o
164
+ * @return {T}
165
+ */
166
+ return (o) => o;
152
167
  default:
153
168
  case 'string':
154
- return DEFAULT_STRING_PARSER;
169
+ /**
170
+ * Doesn't support `Symbol` types
171
+ * @see https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String#string_coercion
172
+ * @param {any} v
173
+ * @return {string}
174
+ */
175
+ return (v) => `${v}`;
155
176
  }
156
177
  }
157
178
 
179
+ /**
180
+ * @param {(data: Partial<any>) => any} fn
181
+ * @param {...any} args
182
+ * @this {any}
183
+ * @return {{
184
+ * props: {
185
+ * this: string[],
186
+ * args: string[][],
187
+ * },
188
+ * deepPropStrings: {
189
+ * this: string[],
190
+ * args: string[][],
191
+ * },
192
+ * deepProps: {
193
+ * this: string[][],
194
+ * args: string[][][],
195
+ * },
196
+ * defaultValue: any,
197
+ * reusable: boolean,
198
+ * }}
199
+ */
200
+ export function observeFunction(fn, ...args) {
201
+ /** @type {Set<string>} */
202
+ const thisPoked = new Set();
203
+ /** @type {Set<string>} */
204
+ const thisPokedDeep = new Set();
205
+
206
+ const argWatchers = args.map((arg) => {
207
+ const poked = new Set();
208
+ const pokedDeep = new Set();
209
+ const proxy = buildProxy(arg, poked, pokedDeep);
210
+ return { poked, pokedDeep, proxy };
211
+ });
212
+
213
+ const thisProxy = buildProxy(this ?? {}, thisPoked, thisPokedDeep);
214
+ const defaultValue = fn.apply(thisProxy, argWatchers.map((watcher) => watcher.proxy));
215
+ /* Arrow functions can reused if they don't poke `this` */
216
+ const reusable = fn.name ? true : !thisPoked.size;
217
+
218
+ return {
219
+ props: {
220
+ this: [...thisPoked],
221
+ args: argWatchers.map((watcher) => [...watcher.poked]),
222
+ },
223
+ deepPropStrings: {
224
+ this: [...thisPokedDeep],
225
+ args: argWatchers.map((watcher) => [...watcher.pokedDeep]),
226
+ },
227
+ deepProps: {
228
+ this: [...thisPokedDeep].map((deepPropString) => deepPropString.split('.')),
229
+ args: argWatchers.map((watcher) => [...watcher.pokedDeep].map((deepPropString) => deepPropString.split('.'))),
230
+ },
231
+ defaultValue,
232
+ reusable,
233
+ };
234
+ }
235
+
236
+ /** @return {null} */
237
+ function defaultNullParser() { return null; }
238
+
158
239
  /**
159
240
  * @template {string} K
160
241
  * @template {ObserverPropertyType} [T1=any]
161
- * @template {any} [T2=import('./typings.js').ParsedObserverPropertyType<T1>]
242
+ * @template {any} [T2=ParsedObserverPropertyType<T1>]
243
+ * @template {Object} [C=any]
162
244
  * @param {K} name
163
- * @param {T1|import('./typings.js').ObserverOptions<T1,T2>} [typeOrOptions='string']
164
- * @param {any} object
165
- * @return {import('./typings.js').ObserverConfiguration<T1,T2,K> & import('./typings.js').ObserverOptions<T1,T2>}
245
+ * @param {T1|ObserverOptions<T1,T2>} [typeOrOptions='string']
246
+ * @param {any} [object]
247
+ * @return {ObserverConfiguration<T1,T2,C,K> & ObserverOptions<T1,T2,C>}
166
248
  */
167
249
  export function parseObserverOptions(name, typeOrOptions, object) {
168
- /** @type {Partial<import('./typings.js').ObserverOptions<T1,T2>>} */
169
- const options = {
170
- ...((typeof typeOrOptions === 'string') ? { type: typeOrOptions } : typeOrOptions),
171
- };
250
+ /** @type {Partial<ObserverOptions<T1,T2>>} */
251
+ const options = (typeof typeOrOptions === 'string')
252
+ ? { type: typeOrOptions }
253
+ : typeOrOptions;
254
+
255
+ let {
256
+ watchers, value, readonly,
257
+ empty, type,
258
+ enumerable, reflect, attr,
259
+ nullable, parser, nullParser,
260
+ get,
261
+ is, diff,
262
+ props,
263
+ } = options;
264
+
265
+ watchers ??= [];
266
+ readonly ??= false;
267
+
268
+ if (empty === undefined) {
269
+ empty = null;
270
+ }
172
271
 
173
- let { enumerable, attr, reflect } = options;
174
- const { type, empty, changedCallback } = options;
272
+ value ??= empty;
273
+
274
+ if (get && !props) {
275
+ // Custom `get` uses computed values.
276
+ // Invalidate computed value when dependent `prop` changes
277
+ const observeResult = observeFunction(get.bind(object), object, () => value);
278
+ value ??= observeResult.defaultValue;
279
+ const uniqueProps = new Set([
280
+ ...observeResult.props.this,
281
+ ...observeResult.props.args[0],
282
+ ]);
283
+ props = uniqueProps;
284
+ }
175
285
 
176
286
  /** @type {ObserverPropertyType} */
177
- let parsedType = type;
178
- if (parsedType == null) {
179
- // Use .value or .get() to parse type
180
- const value = options.value ?? empty ?? options.get?.call(object ?? {}, object ?? {});
287
+ if (!type) {
181
288
  if (value == null) {
182
- parsedType = 'string';
289
+ // @ts-ignore
290
+ type = 'string';
183
291
  } else {
184
292
  const parsed = typeof value;
185
- parsedType = (parsed === 'number')
293
+ // @ts-ignore
294
+ type = (parsed === 'number')
186
295
  ? (Number.isInteger(value) ? 'integer' : 'number')
187
296
  : parsed;
188
297
  }
189
298
  }
190
299
 
191
300
  enumerable ??= name[0] !== '_';
192
- reflect ??= enumerable ? parsedType !== 'object' : (attr ? 'write' : false);
301
+ nullable ??= (type === 'boolean') ? false : (empty == null);
302
+ if (!nullable) {
303
+ empty ??= emptyFromType(type);
304
+ value ??= empty;
305
+ }
306
+
307
+ reflect ??= enumerable ? (type !== 'object') : (attr ? 'write' : false);
193
308
  attr ??= (reflect ? attrNameFromPropName(name) : null);
194
309
 
195
310
  // if defined ? value
196
311
  // else if boolean ? false
197
312
  // else if onNullish ? false
198
313
  // else if empty == null
199
- const parser = options.parser ?? defaultParserFromType(parsedType);
200
- let nullParser = options.nullParser;
201
- let parsedEmpty = empty ?? null;
314
+ parser ??= defaultParserFromType(type);
202
315
  if (!nullParser) {
203
- const nullable = options.nullable ?? (
204
- parsedType === 'boolean'
205
- ? false
206
- : (empty == null));
207
316
  if (nullable) {
208
- nullParser = DEFAULT_NULL_PARSER;
317
+ nullParser = defaultNullParser;
209
318
  } else {
210
- parsedEmpty ??= emptyFromType(parsedType);
211
- nullParser = parsedEmpty === null ? () => emptyFromType(parsedType) : () => parsedEmpty;
319
+ nullParser = (empty === null)
320
+ ? () => emptyFromType(type)
321
+ : () => empty;
212
322
  }
213
323
  }
214
324
 
215
- let isFn = options.is;
216
- if (!isFn) {
217
- isFn = parsedType === 'object'
218
- ? DEFAULT_OBJECT_COMPARATOR
219
- : ((parsedType === 'array') ? DEFAULT_ARRAY_COMPARATOR : Object.is);
220
- }
325
+ is ??= (type === 'object')
326
+ ? (a, b) => !hasMergePatch(a, b)
327
+ : ((type === 'array') ? () => false : Object.is);
221
328
 
222
- const diff = 'diff' in options
223
- ? options.diff
224
- : ((parsedType === 'object') ? DEFAULT_OBJECT_DIFF : null);
329
+ if (diff === undefined) {
330
+ // @ts-ignore
331
+ diff = ((type === 'object') ? (a, b) => buildMergePatch(a, b, 'reference') : null);
332
+ }
225
333
 
226
334
  return {
227
335
  ...options,
228
- type: parsedType,
229
- is: isFn,
336
+ type,
337
+ is,
230
338
  diff,
231
339
  attr,
232
340
  reflect,
233
- readonly: options.readonly ?? false,
341
+ readonly,
234
342
  enumerable,
235
- value: options.value ?? parsedEmpty,
343
+ value,
236
344
  parser,
237
345
  nullParser,
238
346
  key: name,
239
- changedCallback,
240
- watchers: options.watchers ?? [],
241
- values: options.values ?? new WeakMap(),
242
- computedValues: options.computedValues ?? new WeakMap(),
243
- attributeChangedCallback: options.attributeChangedCallback,
244
- needsSelfInvalidation: options.needsSelfInvalidation ?? new WeakSet(),
347
+ // @ts-ignore Can't cast
348
+ props,
349
+ // @ts-ignore Can't cast
350
+ watchers,
245
351
  };
246
352
  }
247
353
 
248
- const INIT_SYMBOL = Symbol('PROP_INIT');
249
-
250
- /** @type {Partial<import('./typings.js').ObserverConfiguration<?,?,?>>} */
251
- const DEFAULT_OBSERVER_CONFIGURATION = {
252
- nullParser: DEFAULT_NULL_PARSER,
253
- is: Object.is,
254
- INIT_SYMBOL,
255
- };
256
-
257
354
  /**
258
- * @this {import('./typings.js').ObserverConfiguration<?,?,?>}
355
+ * @this {ObserverConfiguration<?,?,?>}
259
356
  * @param {*} value
260
357
  */
261
358
  export function parsePropertyValue(value) {
@@ -263,120 +360,84 @@ export function parsePropertyValue(value) {
263
360
  newValue = value == null
264
361
  ? this.nullParser.call(this, value)
265
362
  : this.parser.call(this, newValue);
363
+ return newValue;
266
364
  }
267
365
 
268
366
  /**
269
- * @param {(data: Partial<any>) => any} fn
270
- * @param {...any} args
271
- * @this {any}
272
- * @return {{
273
- * props: {
274
- * this: string[],
275
- * args: string[][],
276
- * },
277
- * deepPropStrings: {
278
- * this: string[],
279
- * args: string[][],
280
- * },
281
- * deepProps: {
282
- * this: string[][],
283
- * args: string[][][],
284
- * },
285
- * defaultValue: any,
286
- * reusable: boolean,
287
- * }}
367
+ * @param {ObserverConfiguration<?,?,?,?>} config
368
+ * @param {any} oldValue
369
+ * @param {any} value
370
+ * @return {boolean} changed
288
371
  */
289
- export function observeFunction(fn, ...args) {
290
- /** @type {Set<string>} */
291
- const thisPoked = new Set();
292
- /** @type {Set<string>} */
293
- const thisPokedDeep = new Set();
372
+ function detectChange(config, oldValue, value) {
373
+ if (config.get) {
374
+ // TODO: Custom getter vs parser
375
+ }
294
376
 
295
- const argWatchers = args.map((arg) => {
296
- const poked = new Set();
297
- const pokedDeep = new Set();
298
- const proxy = buildProxy(arg, poked, pokedDeep);
299
- return { poked, pokedDeep, proxy };
300
- });
377
+ // Compute real new value after parsing
378
+ const newValue = (value == null)
379
+ ? config.nullParser.call(this, value)
380
+ : config.parser.call(this, value);
301
381
 
302
- const thisProxy = buildProxy(this ?? {}, thisPoked, thisPokedDeep);
303
- const defaultValue = fn.apply(thisProxy, argWatchers.map((watcher) => watcher.proxy));
304
- /* Arrow functions can reused if they don't poke `this` */
305
- const reusable = fn.name ? true : !thisPoked.size;
382
+ // Default change is the newValue
383
+ let changes = newValue;
306
384
 
307
- return {
308
- props: {
309
- this: [...thisPoked],
310
- args: argWatchers.map((watcher) => [...watcher.poked]),
311
- },
312
- deepPropStrings: {
313
- this: [...thisPokedDeep],
314
- args: argWatchers.map((watcher) => [...watcher.pokedDeep]),
315
- },
316
- deepProps: {
317
- this: [...thisPokedDeep].map((deepPropString) => deepPropString.split('.')),
318
- args: argWatchers.map((watcher) => [...watcher.pokedDeep].map((deepPropString) => deepPropString.split('.'))),
319
- },
320
- defaultValue,
321
- reusable,
322
- };
385
+ // Null check
386
+ if (oldValue == null) {
387
+ if (newValue == null) {
388
+ // Both nullish
389
+ return false;
390
+ }
391
+ } else if (newValue != null) {
392
+ // Both non-null, compare
393
+ if (config.diff) {
394
+ // Custom change diff
395
+ changes = config.diff.call(this, oldValue, newValue);
396
+ if (changes == null) {
397
+ // No difference
398
+ return false;
399
+ }
400
+ } else if (config.is.call(this, oldValue, newValue)) {
401
+ // Non-equal
402
+ return false;
403
+ }
404
+ }
405
+
406
+ // Commit value
407
+ if (config.values) {
408
+ config.values.set(this, newValue);
409
+ } else {
410
+ config.values = new WeakMap([[this, newValue]]);
411
+ }
412
+
413
+ // Emit change
414
+
415
+ config.propChangedCallback?.call(this, config.key, oldValue, newValue, changes);
416
+ config.changedCallback?.call(this, oldValue, newValue, changes);
417
+
418
+ return true;
323
419
  }
324
420
 
325
421
  /**
326
422
  * @template {ObserverPropertyType} T1
327
423
  * @template {any} T2
328
- * @template {string} K
329
- * @template [C=any]
424
+ * @template {Object} C
425
+ * @template {keyof C & string} K
330
426
  * @param {C} object
331
427
  * @param {K} key
332
- * @param {import('./typings.js').ObserverOptions<T1, T2, C>} options
333
- * @return {import('./typings.js').ObserverConfiguration<T1,T2,K,C>}
428
+ * @param {ObserverOptions<T1, T2, C>} options
429
+ * @return {ObserverConfiguration<T1,T2,C,K>}
334
430
  */
335
431
  export function defineObservableProperty(object, key, options) {
336
- /** @type {import('./typings.js').ObserverConfiguration<T1,T2,K,C>} */
337
- const config = {
338
- ...DEFAULT_OBSERVER_CONFIGURATION,
339
- ...parseObserverOptions(key, options, object),
340
- changedCallback: options.changedCallback,
341
- };
432
+ const config = /** @type {ObserverConfiguration<T1,T2,C,K>} */ (
433
+ parseObserverOptions(key, options, object));
342
434
 
343
- /**
344
- * @param {T2} oldValue
345
- * @param {T2} value
346
- * @return {boolean} changed
347
- */
348
- function detectChange(oldValue, value) {
349
- if (config.get) {
350
- // TODO: Custom getter vs parser
351
- }
352
- let newValue = value;
353
- newValue = (value == null)
354
- ? config.nullParser.call(this, value)
355
- : config.parser.call(this, newValue);
356
-
357
- let changes = newValue;
358
- if (oldValue == null) {
359
- if (newValue == null) return false; // Both nullish
360
- } else if (newValue != null) {
361
- // if (oldValue === newValue) return false;
362
- if (config.diff) {
363
- changes = config.diff.call(this, oldValue, newValue);
364
- if (changes == null) return false;
365
- } else if (config.is.call(this, oldValue, newValue)) return false;
366
- }
367
-
368
- config.values.set(this, newValue);
369
- // console.log(key, 'value.set', newValue);
370
- config.propChangedCallback?.call(this, key, oldValue, newValue, changes);
371
- config.changedCallback?.call(this, oldValue, newValue, changes);
372
- return true;
373
- }
374
435
  /**
375
436
  * @this {C}
376
437
  * @return {T2}
377
438
  */
378
439
  function internalGet() {
379
- return config.values.has(this) ? config.values.get(this) : config.value;
440
+ return config.values?.has(this) ? config.values.get(this) : config.value;
380
441
  }
381
442
 
382
443
  /**
@@ -385,75 +446,66 @@ export function defineObservableProperty(object, key, options) {
385
446
  * @return {void}
386
447
  */
387
448
  function internalSet(value) {
449
+ // @ts-ignore
388
450
  const oldValue = this[key];
389
- // console.log(key, 'internalSet', oldValue, '=>', value);
390
- detectChange.call(this, oldValue, value);
451
+ detectChange.call(this, config, oldValue, value);
391
452
  }
392
453
 
393
454
  /** @return {void} */
394
455
  function onInvalidate() {
395
456
  // Current value is now invalidated. Recompute and check if changed
396
- const oldValue = config.computedValues.get(this);
457
+ // eslint-disable-next-line no-multi-assign
458
+
459
+ const oldValue = config.computedValues?.get(this);
397
460
  const newValue = this[key];
398
- // console.debug('observe: onInvalidate called for', key, oldValue, '=>', newValue, this);
399
- config.needsSelfInvalidation.delete(this);
400
- detectChange.call(this, oldValue, newValue);
461
+ config.needsSelfInvalidation?.delete(this);
462
+ detectChange.call(this, config, oldValue, newValue);
401
463
  }
402
464
 
403
- if (config.get) {
404
- // Custom `get` uses computed values.
405
- // Invalidate computed value when dependent `prop` changes
406
- const observeResult = observeFunction(config.get.bind(object), object, internalGet.bind(object));
407
- const uniqueProps = new Set([
408
- ...observeResult.props.this,
409
- ...observeResult.props.args[0],
410
- ]);
411
- for (const prop of uniqueProps) {
412
- // @ts-ignore keyof C
465
+ if (config.props) {
466
+ for (const prop of config.props) {
413
467
  config.watchers.push([prop, onInvalidate]);
414
468
  }
469
+ }
470
+
471
+ /**
472
+ * @this {C}
473
+ * @return {T2}
474
+ */
475
+ function cachedGet() {
476
+ const newValue = config.get.call(this, this, internalGet.bind(this));
477
+ // Store computed value internally. Used by onInvalidate to get previous value
478
+ // eslint-disable-next-line no-multi-assign
479
+ const computedValues = (config.computedValues ??= new WeakMap());
480
+ computedValues.set(this, newValue);
481
+ return newValue;
482
+ }
415
483
 
416
- // TODO: May be able to cache value if props are present
484
+ /**
485
+ * @this {C}
486
+ * @param {T2} value
487
+ * @return {void}
488
+ */
489
+ function cachedSet(value) {
490
+ if (config.needsSelfInvalidation) {
491
+ config.needsSelfInvalidation.add(this);
492
+ } else {
493
+ config.needsSelfInvalidation = new WeakSet([this]);
494
+ }
495
+ const oldValue = this[key];
496
+ config.set.call(this, value, internalSet.bind(this));
497
+ const newValue = this[key];
498
+ if (!config.needsSelfInvalidation.has(this)) return;
499
+ config.needsSelfInvalidation.delete(this);
500
+ detectChange.call(this, config, oldValue, newValue);
417
501
  }
502
+
418
503
  /** @type {Partial<PropertyDescriptor>} */
419
504
  const descriptor = {
420
505
  enumerable: config.enumerable,
421
506
  configurable: true,
422
- /**
423
- * @this {C}
424
- * @return {T2}
425
- */
426
- get() {
427
- if (config.get) {
428
- const newValue = config.get.call(this, this, internalGet.bind(this));
429
- // Store computed value internally. Used by onInvalidate to get previous value
430
- config.computedValues.set(this, newValue);
431
- return newValue;
432
- }
433
- return internalGet.call(this);
434
- },
435
- /**
436
- * @this {C}
437
- * @param {T2} value
438
- * @return {void}
439
- */
440
- set(value) {
441
- if (value === INIT_SYMBOL) {
442
- // console.log(key, 'returning due to INIT');
443
- return;
444
- }
445
- if (config.set) {
446
- config.needsSelfInvalidation.add(this);
447
- const oldValue = this[key];
448
- config.set.call(this, value, internalSet.bind(this));
449
- const newValue = this[key];
450
- if (!config.needsSelfInvalidation.has(this)) return;
451
- config.needsSelfInvalidation.delete(this);
452
- detectChange.call(this, oldValue, newValue);
453
- } else {
454
- internalSet.call(this, value);
455
- }
456
- },
507
+ get: config.get ? cachedGet : internalGet,
508
+ set: config.set ? cachedSet : internalSet,
457
509
  };
458
510
 
459
511
  Object.defineProperty(object, key, descriptor);