@shortfuse/materialdesignweb 0.5.0 → 0.7.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 (418) hide show
  1. package/README.md +155 -77
  2. package/bin/generate-css.js +12 -0
  3. package/components/Badge.css +30 -0
  4. package/components/Badge.js +15 -0
  5. package/components/Body.css +14 -0
  6. package/components/Body.js +7 -0
  7. package/components/BottomAppBar.css +23 -0
  8. package/components/BottomAppBar.js +25 -0
  9. package/components/Box.css +31 -0
  10. package/components/Box.js +24 -0
  11. package/components/Button.css +146 -0
  12. package/components/Button.js +95 -0
  13. package/components/Button.md +61 -0
  14. package/components/Card.css +109 -0
  15. package/components/Card.js +82 -0
  16. package/components/Checkbox.css +77 -0
  17. package/components/Checkbox.js +59 -0
  18. package/components/CheckboxIcon.css +89 -0
  19. package/components/CheckboxIcon.js +41 -0
  20. package/components/Chip.css +35 -0
  21. package/components/Chip.js +22 -0
  22. package/components/Dialog.css +235 -0
  23. package/components/Dialog.js +327 -0
  24. package/components/DialogActions.js +13 -0
  25. package/components/Divider.css +41 -0
  26. package/components/Divider.js +13 -0
  27. package/components/ExtendedFab.css +24 -0
  28. package/components/ExtendedFab.js +11 -0
  29. package/components/Fab.css +23 -0
  30. package/components/Fab.js +26 -0
  31. package/components/FilterChip.css +80 -0
  32. package/components/FilterChip.js +51 -0
  33. package/components/Headline.css +14 -0
  34. package/components/Headline.js +33 -0
  35. package/components/Icon.css +76 -0
  36. package/components/Icon.js +174 -0
  37. package/components/IconButton.css +151 -0
  38. package/components/IconButton.js +65 -0
  39. package/components/Input.js +16 -0
  40. package/components/Label.css +14 -0
  41. package/components/Label.js +7 -0
  42. package/components/Layout.css +19 -0
  43. package/components/Layout.js +12 -0
  44. package/components/List.css +12 -0
  45. package/components/List.js +17 -0
  46. package/components/ListItem.css +224 -0
  47. package/components/ListItem.js +112 -0
  48. package/components/ListOption.css +34 -0
  49. package/components/ListOption.js +122 -0
  50. package/components/ListSelect.css +9 -0
  51. package/components/ListSelect.js +206 -0
  52. package/components/Menu.css +171 -0
  53. package/components/Menu.js +470 -0
  54. package/components/MenuItem.css +53 -0
  55. package/components/MenuItem.js +215 -0
  56. package/components/Nav.css +17 -0
  57. package/components/Nav.js +23 -0
  58. package/components/NavBar.css +34 -0
  59. package/components/NavBar.js +88 -0
  60. package/components/NavBarItem.css +41 -0
  61. package/components/NavBarItem.js +7 -0
  62. package/components/NavDrawer.css +31 -0
  63. package/components/NavDrawer.js +13 -0
  64. package/components/NavDrawerItem.css +42 -0
  65. package/components/NavDrawerItem.js +12 -0
  66. package/components/NavItem.css +181 -0
  67. package/components/NavItem.js +83 -0
  68. package/components/NavRail.css +47 -0
  69. package/components/NavRail.js +17 -0
  70. package/components/NavRailItem.css +25 -0
  71. package/components/NavRailItem.js +7 -0
  72. package/components/Option.js +91 -0
  73. package/components/Outline.css +138 -0
  74. package/components/Pane.css +261 -0
  75. package/components/Pane.js +21 -0
  76. package/components/Progress.css +74 -0
  77. package/components/Progress.js +67 -0
  78. package/components/ProgressCircle.css +226 -0
  79. package/components/ProgressLine.css +155 -0
  80. package/components/Radio.css +83 -0
  81. package/components/Radio.js +42 -0
  82. package/components/RadioIcon.css +73 -0
  83. package/components/RadioIcon.js +37 -0
  84. package/components/Ripple.css +74 -0
  85. package/components/Ripple.js +114 -0
  86. package/components/SegmentedButton.css +94 -0
  87. package/components/SegmentedButton.js +49 -0
  88. package/components/SegmentedButtonGroup.css +12 -0
  89. package/components/SegmentedButtonGroup.js +44 -0
  90. package/components/Select.css +52 -0
  91. package/components/Select.js +71 -0
  92. package/components/Shape.css +132 -0
  93. package/components/Shape.js +25 -0
  94. package/components/Slider.css +306 -0
  95. package/components/Slider.js +206 -0
  96. package/components/Snackbar.css +80 -0
  97. package/components/Snackbar.js +75 -0
  98. package/components/Surface.css +10 -0
  99. package/components/Surface.js +23 -0
  100. package/components/Switch.css +63 -0
  101. package/components/Switch.js +127 -0
  102. package/components/SwitchIcon.css +177 -0
  103. package/components/SwitchIcon.js +89 -0
  104. package/components/SwitchIconAnimations.css +89 -0
  105. package/components/Tab.css +85 -0
  106. package/components/Tab.js +103 -0
  107. package/components/TabContent.js +151 -0
  108. package/components/TabList.css +129 -0
  109. package/components/TabList.js +309 -0
  110. package/components/TabPanel.js +37 -0
  111. package/components/TextArea.css +93 -0
  112. package/components/TextArea.js +229 -0
  113. package/components/Title.css +14 -0
  114. package/components/Title.js +15 -0
  115. package/components/Tooltip.css +40 -0
  116. package/components/Tooltip.js +22 -0
  117. package/components/TopAppBar.css +209 -0
  118. package/components/TopAppBar.js +201 -0
  119. package/core/Composition.js +988 -0
  120. package/core/CustomElement.js +844 -0
  121. package/core/ICustomElement.d.ts +288 -0
  122. package/core/ICustomElement.js +1 -0
  123. package/core/css.js +51 -0
  124. package/core/customTypes.js +125 -0
  125. package/core/dom.js +56 -154
  126. package/core/identify.js +40 -0
  127. package/core/observe.js +410 -0
  128. package/core/template.js +121 -0
  129. package/core/typings.d.ts +135 -0
  130. package/core/typings.js +1 -0
  131. package/mixins/AriaReflectorMixin.js +42 -0
  132. package/mixins/AriaToolbarMixin.js +13 -0
  133. package/mixins/ControlMixin.css +57 -0
  134. package/mixins/ControlMixin.js +212 -0
  135. package/mixins/DensityMixin.css +40 -0
  136. package/mixins/DensityMixin.js +11 -0
  137. package/mixins/FlexableMixin.css +79 -0
  138. package/mixins/FlexableMixin.js +32 -0
  139. package/mixins/FormAssociatedMixin.js +170 -0
  140. package/mixins/InputMixin.js +335 -0
  141. package/mixins/KeyboardNavMixin.js +244 -0
  142. package/mixins/RTLObserverMixin.js +35 -0
  143. package/mixins/ResizeObserverMixin.js +38 -0
  144. package/mixins/RippleMixin.css +12 -0
  145. package/mixins/RippleMixin.js +115 -0
  146. package/mixins/ScrollListenerMixin.js +100 -0
  147. package/mixins/ShapeMixin.css +135 -0
  148. package/mixins/ShapeMixin.js +31 -0
  149. package/mixins/StateMixin.css +82 -0
  150. package/mixins/StateMixin.js +114 -0
  151. package/mixins/SurfaceMixin.css +150 -0
  152. package/mixins/SurfaceMixin.js +32 -0
  153. package/mixins/TextFieldMixin.css +657 -0
  154. package/mixins/TextFieldMixin.js +121 -0
  155. package/mixins/ThemableMixin.css +204 -0
  156. package/mixins/ThemableMixin.js +16 -0
  157. package/mixins/TooltipTriggerMixin.css +27 -0
  158. package/mixins/TooltipTriggerMixin.js +366 -0
  159. package/mixins/TouchTargetMixin.css +26 -0
  160. package/mixins/TouchTargetMixin.js +9 -0
  161. package/package.json +54 -49
  162. package/theming/index.js +594 -0
  163. package/theming/loader.js +24 -0
  164. package/utils/cli.js +11 -0
  165. package/utils/color_keywords.js +151 -0
  166. package/utils/hct/Cam16.js +298 -0
  167. package/utils/hct/CorePalette.js +84 -0
  168. package/utils/hct/Hct.js +172 -0
  169. package/utils/hct/Scheme.js +587 -0
  170. package/utils/hct/TonalPalette.js +68 -0
  171. package/utils/hct/ViewingConditions.js +136 -0
  172. package/utils/hct/blend.js +93 -0
  173. package/utils/hct/colorUtils.js +302 -0
  174. package/utils/hct/hctSolver.js +559 -0
  175. package/utils/hct/helper.js +182 -0
  176. package/utils/hct/mathUtils.js +153 -0
  177. package/utils/jsonMergePatch.js +100 -0
  178. package/utils/jsx-runtime.js +101 -0
  179. package/utils/popup.js +117 -0
  180. package/utils/svg.js +129 -0
  181. package/.browserslistrc +0 -4
  182. package/.eslintrc.json +0 -204
  183. package/.stylelintrc.json +0 -645
  184. package/.vscode/launch.json +0 -31
  185. package/.vscode/settings.json +0 -3
  186. package/.vscode/tasks.json +0 -32
  187. package/CHANGELOG.md +0 -36
  188. package/CODE_OF_CONDUCT.md +0 -46
  189. package/adapters/datatable/column.js +0 -176
  190. package/adapters/datatable/index.js +0 -960
  191. package/adapters/dom/index.js +0 -586
  192. package/adapters/list/index.js +0 -69
  193. package/adapters/search/index.js +0 -495
  194. package/components/appbar/_spec.scss +0 -165
  195. package/components/appbar/_theme.scss +0 -0
  196. package/components/appbar/index.scss +0 -2
  197. package/components/banner/_spec.scss +0 -83
  198. package/components/banner/_theme.scss +0 -0
  199. package/components/banner/index.scss +0 -2
  200. package/components/bottomnav/README.md +0 -85
  201. package/components/bottomnav/_spec.scss +0 -149
  202. package/components/bottomnav/_theme.scss +0 -0
  203. package/components/bottomnav/index.js +0 -117
  204. package/components/bottomnav/index.scss +0 -2
  205. package/components/bottomnav/item.js +0 -88
  206. package/components/button/README.md +0 -61
  207. package/components/button/_spec.scss +0 -162
  208. package/components/button/_theme.scss +0 -42
  209. package/components/button/index.eta +0 -32
  210. package/components/button/index.js +0 -43
  211. package/components/button/index.pug +0 -18
  212. package/components/button/index.scss +0 -2
  213. package/components/card/_spec.scss +0 -241
  214. package/components/card/_theme.scss +0 -0
  215. package/components/card/index.scss +0 -2
  216. package/components/chip/_spec.scss +0 -111
  217. package/components/chip/_theme.scss +0 -105
  218. package/components/chip/index.js +0 -23
  219. package/components/chip/index.scss +0 -2
  220. package/components/chip/item.js +0 -20
  221. package/components/datatable/_spec.scss +0 -225
  222. package/components/datatable/_theme.scss +0 -128
  223. package/components/datatable/cell.js +0 -44
  224. package/components/datatable/columnheader.js +0 -46
  225. package/components/datatable/index.js +0 -374
  226. package/components/datatable/index.scss +0 -2
  227. package/components/datatable/row.js +0 -48
  228. package/components/datatable/rowheader.js +0 -18
  229. package/components/dialog/_spec.scss +0 -203
  230. package/components/dialog/_theme.scss +0 -7
  231. package/components/dialog/index.js +0 -601
  232. package/components/dialog/index.scss +0 -2
  233. package/components/divider/_spec.scss +0 -11
  234. package/components/divider/_theme.scss +0 -0
  235. package/components/divider/index.scss +0 -2
  236. package/components/elevation/_spec.scss +0 -9
  237. package/components/elevation/_theme.scss +0 -0
  238. package/components/elevation/index.scss +0 -2
  239. package/components/fab/_spec.scss +0 -210
  240. package/components/fab/_theme.scss +0 -0
  241. package/components/fab/index.js +0 -99
  242. package/components/fab/index.scss +0 -2
  243. package/components/grid/_spec.scss +0 -169
  244. package/components/grid/_theme.scss +0 -0
  245. package/components/grid/index.scss +0 -2
  246. package/components/layout/_mixins.scss +0 -11
  247. package/components/layout/_spec.scss +0 -916
  248. package/components/layout/_theme.scss +0 -19
  249. package/components/layout/index.js +0 -454
  250. package/components/layout/index.scss +0 -2
  251. package/components/list/_spec.scss +0 -363
  252. package/components/list/_theme.scss +0 -102
  253. package/components/list/content.js +0 -106
  254. package/components/list/index.js +0 -256
  255. package/components/list/index.scss +0 -2
  256. package/components/list/item.js +0 -167
  257. package/components/list/secondary.js +0 -45
  258. package/components/menu/_spec.scss +0 -329
  259. package/components/menu/_theme.scss +0 -0
  260. package/components/menu/index.js +0 -705
  261. package/components/menu/index.scss +0 -2
  262. package/components/menu/item.js +0 -231
  263. package/components/progress/_spec.scss +0 -156
  264. package/components/progress/_theme.scss +0 -0
  265. package/components/progress/index.js +0 -36
  266. package/components/progress/index.scss +0 -2
  267. package/components/selection/_spec.scss +0 -376
  268. package/components/selection/_theme.scss +0 -134
  269. package/components/selection/index.eta +0 -60
  270. package/components/selection/index.js +0 -70
  271. package/components/selection/index.pug +0 -30
  272. package/components/selection/index.scss +0 -2
  273. package/components/selection/input.js +0 -54
  274. package/components/selection/radiogroup.js +0 -40
  275. package/components/slider/_spec.scss +0 -59
  276. package/components/slider/_theme.scss +0 -0
  277. package/components/slider/index.scss +0 -2
  278. package/components/snackbar/_spec.scss +0 -150
  279. package/components/snackbar/_theme.scss +0 -0
  280. package/components/snackbar/index.js +0 -338
  281. package/components/snackbar/index.scss +0 -2
  282. package/components/tab/_spec.scss +0 -220
  283. package/components/tab/_theme.scss +0 -0
  284. package/components/tab/content.js +0 -210
  285. package/components/tab/index.js +0 -257
  286. package/components/tab/index.scss +0 -2
  287. package/components/tab/item.js +0 -88
  288. package/components/tab/list.js +0 -196
  289. package/components/tab/panel.js +0 -54
  290. package/components/textfield/README.md +0 -179
  291. package/components/textfield/_spec.scss +0 -763
  292. package/components/textfield/_theme.scss +0 -264
  293. package/components/textfield/index.eta +0 -74
  294. package/components/textfield/index.js +0 -160
  295. package/components/textfield/index.pug +0 -30
  296. package/components/textfield/index.scss +0 -2
  297. package/components/tooltip/_spec.scss +0 -185
  298. package/components/tooltip/_theme.scss +0 -0
  299. package/components/tooltip/index.scss +0 -2
  300. package/components/type/_spec.scss +0 -227
  301. package/components/type/_theme.scss +0 -0
  302. package/components/type/index.scss +0 -2
  303. package/core/_breakpoint.scss +0 -189
  304. package/core/_elevation.scss +0 -78
  305. package/core/_length.scss +0 -8
  306. package/core/_motion.scss +0 -31
  307. package/core/_platform.scss +0 -12
  308. package/core/_type.scss +0 -128
  309. package/core/aria/attributes.js +0 -141
  310. package/core/aria/button.js +0 -49
  311. package/core/aria/keyboard.js +0 -92
  312. package/core/aria/rovingtabindex.js +0 -175
  313. package/core/aria/tab.js +0 -59
  314. package/core/document/index.js +0 -39
  315. package/core/overlay/_spec.scss +0 -28
  316. package/core/overlay/_theme.scss +0 -147
  317. package/core/overlay/index.js +0 -95
  318. package/core/overlay/index.scss +0 -2
  319. package/core/ripple/_spec.scss +0 -196
  320. package/core/ripple/_theme.scss +0 -20
  321. package/core/ripple/index.js +0 -286
  322. package/core/ripple/index.scss +0 -2
  323. package/core/theme/_aliases.scss +0 -15
  324. package/core/theme/_config.scss +0 -8
  325. package/core/theme/_functions.scss +0 -22
  326. package/core/theme/_palettes.scss +0 -405
  327. package/core/theme/_spec.scss +0 -0
  328. package/core/theme/_theme.scss +0 -268
  329. package/core/theme/index.js +0 -50
  330. package/core/theme/index.scss +0 -4
  331. package/core/throttler.js +0 -42
  332. package/core/transition/index.js +0 -465
  333. package/docs/_flex.scss +0 -28
  334. package/docs/_menuoptions.js +0 -183
  335. package/docs/_partials/_androidnavbar.eta +0 -5
  336. package/docs/_partials/_androidstatusbar.eta +0 -13
  337. package/docs/_partials/_appbar.eta +0 -27
  338. package/docs/_partials/_buttontest.eta +0 -31
  339. package/docs/_partials/_header.eta +0 -146
  340. package/docs/_partials/_navlistitem.eta +0 -16
  341. package/docs/_partials/_target.eta +0 -1
  342. package/docs/_sample-utils.js +0 -88
  343. package/docs/_storage.js +0 -33
  344. package/docs/docs.scss +0 -331
  345. package/docs/framework.scss +0 -26
  346. package/docs/index.eta +0 -12
  347. package/docs/index.js +0 -7
  348. package/docs/pages/appbar.eta +0 -108
  349. package/docs/pages/appbar.js +0 -0
  350. package/docs/pages/bottomnav.eta +0 -188
  351. package/docs/pages/bottomnav.js +0 -118
  352. package/docs/pages/button.eta +0 -124
  353. package/docs/pages/button.js +0 -224
  354. package/docs/pages/card.eta +0 -90
  355. package/docs/pages/card.js +0 -175
  356. package/docs/pages/chip.eta +0 -122
  357. package/docs/pages/chip.js +0 -80
  358. package/docs/pages/color.eta +0 -143
  359. package/docs/pages/color.js +0 -261
  360. package/docs/pages/datatable.eta +0 -323
  361. package/docs/pages/datatable.js +0 -160
  362. package/docs/pages/dialog.eta +0 -184
  363. package/docs/pages/dialog.js +0 -174
  364. package/docs/pages/dom.eta +0 -26
  365. package/docs/pages/dom.js +0 -140
  366. package/docs/pages/elevation.eta +0 -35
  367. package/docs/pages/elevation.js +0 -0
  368. package/docs/pages/fab.eta +0 -99
  369. package/docs/pages/fab.js +0 -43
  370. package/docs/pages/grid.eta +0 -135
  371. package/docs/pages/grid.js +0 -128
  372. package/docs/pages/layout.eta +0 -8
  373. package/docs/pages/layout.js +0 -0
  374. package/docs/pages/list.eta +0 -465
  375. package/docs/pages/list.js +0 -8
  376. package/docs/pages/menu.eta +0 -274
  377. package/docs/pages/menu.js +0 -213
  378. package/docs/pages/overlay.eta +0 -69
  379. package/docs/pages/overlay.js +0 -3
  380. package/docs/pages/progress.eta +0 -23
  381. package/docs/pages/progress.js +0 -12
  382. package/docs/pages/ripple.eta +0 -27
  383. package/docs/pages/ripple.js +0 -3
  384. package/docs/pages/search.eta +0 -242
  385. package/docs/pages/search.js +0 -226
  386. package/docs/pages/selection.eta +0 -107
  387. package/docs/pages/selection.js +0 -12
  388. package/docs/pages/slider.eta +0 -23
  389. package/docs/pages/slider.js +0 -0
  390. package/docs/pages/snackbar.eta +0 -83
  391. package/docs/pages/snackbar.js +0 -157
  392. package/docs/pages/tab.eta +0 -407
  393. package/docs/pages/tab.js +0 -152
  394. package/docs/pages/textfield.eta +0 -487
  395. package/docs/pages/textfield.js +0 -257
  396. package/docs/pages/tooltip.eta +0 -92
  397. package/docs/pages/tooltip.js +0 -0
  398. package/docs/pages/transition.eta +0 -117
  399. package/docs/pages/transition.js +0 -52
  400. package/docs/pages/type.eta +0 -31
  401. package/docs/pages/type.js +0 -0
  402. package/docs/postrender.js +0 -41
  403. package/docs/prerender.js +0 -16
  404. package/docs/pwa/_dialogs.eta +0 -143
  405. package/docs/pwa/_menus.eta +0 -16
  406. package/docs/pwa/pwa-prerender.js +0 -3
  407. package/docs/pwa/pwa.eta +0 -478
  408. package/docs/pwa/pwa.js +0 -298
  409. package/docs/pwa/pwa.scss +0 -31
  410. package/docs/themes/theme-colored.scss +0 -15
  411. package/docs/themes/theme-default.scss +0 -3
  412. package/index.scss +0 -27
  413. package/jsconfig.json +0 -16
  414. package/scripts/deploy-docs.sh +0 -9
  415. package/templates/index.eta +0 -2
  416. package/templates/index.pug +0 -3
  417. package/tsconfig.json +0 -16
  418. package/webpack.config.js +0 -304
package/core/dom.js CHANGED
@@ -1,180 +1,82 @@
1
+ /* eslint-disable no-bitwise */
2
+
1
3
  /**
2
- * @param {Element} element
3
- * @param {string} className
4
- * @return {Element}
4
+ * @param {any} value
5
+ * @return {?string}
5
6
  */
6
- export function getChildElementByClass(element, className) {
7
- const child = element.getElementsByClassName(className)[0];
8
- if (child && child.parentElement !== element) {
9
- return null;
7
+ export function attrValueFromDataValue(value) {
8
+ switch (value) {
9
+ case undefined:
10
+ case null:
11
+ case false:
12
+ return null;
13
+ case true:
14
+ return '';
15
+ default:
16
+ return `${value}`;
10
17
  }
11
- return child;
12
- }
13
-
14
- /** @return {boolean} */
15
- export function isRtl() {
16
- return document.documentElement.dir === 'rtl';
17
18
  }
18
19
 
19
20
  /**
20
- * @param {EventTarget} eventTarget
21
- * @param {string} type
22
- * @param {Object} [detail]
23
- * @return {boolean}
21
+ * Converts property name to attribute name
22
+ * (Similar to DOMStringMap)
23
+ * @param {string} name
24
+ * @return {string}
24
25
  */
25
- export function dispatchDomEvent(eventTarget, type, detail) {
26
- let event;
27
- if (typeof CustomEvent === 'function') {
28
- event = new CustomEvent(type, {
29
- bubbles: true,
30
- cancelable: true,
31
- detail,
32
- });
33
- } else if (detail == null) {
34
- if (typeof Event === 'function') {
35
- event = new Event(type, {
36
- bubbles: true,
37
- cancelable: true,
38
- });
39
- } else {
40
- event = document.createEvent('Event');
41
- event.initEvent(type, true, true);
26
+ export function attrNameFromPropName(name) {
27
+ const attrNameWords = name.split(/([A-Z])/);
28
+ if (attrNameWords.length === 1) return name;
29
+ return attrNameWords.reduce((prev, curr) => {
30
+ if (prev == null) return curr;
31
+ if (curr.length === 1 && curr.toUpperCase() === curr) {
32
+ return `${prev}-${curr.toLowerCase()}`;
42
33
  }
43
- } else {
44
- event = document.createEvent('CustomEvent');
45
- event.initCustomEvent(type, true, true, detail);
46
- }
47
- return eventTarget.dispatchEvent(event);
34
+ return prev + curr;
35
+ });
48
36
  }
49
37
 
50
- /**
51
- * @param {Element} element
52
- * @param {function(Element, number):boolean|void} fn
53
- * @return {boolean}
54
- */
55
- export function iterateElementSiblings(element, fn) {
56
- let distance = -1;
57
- let sibling = element.previousElementSibling;
58
- while (sibling) {
59
- fn(sibling, distance);
60
- sibling = sibling.previousElementSibling;
61
- distance -= 1;
62
- }
63
- sibling = element.nextElementSibling;
64
- distance = 1;
65
- while (sibling) {
66
- fn(sibling, distance);
67
- sibling = sibling.nextElementSibling;
68
- distance += 1;
69
- }
70
- return false;
71
- }
38
+ const IS_FIREFOX = globalThis?.navigator?.userAgent.includes('Firefox');
72
39
 
73
40
  /**
74
41
  * @param {Element} element
75
- * @param {function(Element, number):boolean|void} fn
76
42
  * @return {boolean}
77
43
  */
78
- export function iterateSomeOfElementSiblings(element, fn) {
79
- let distance = -1;
80
- let sibling = element.previousElementSibling;
81
- while (sibling) {
82
- if (fn(sibling, distance)) {
83
- return true;
84
- }
85
- sibling = sibling.previousElementSibling;
86
- distance -= 1;
87
- }
88
- sibling = element.nextElementSibling;
89
- distance = 1;
90
- while (sibling) {
91
- if (fn(sibling, distance)) {
92
- return true;
93
- }
94
- sibling = sibling.previousElementSibling;
95
- distance += 1;
96
- }
97
- return false;
98
- }
99
-
100
- /**
101
- * @param {Node} node
102
- * @param {boolean} [create]
103
- * @return {?Text}
104
- */
105
- export function getTextNode(node, create) {
106
- for (const childNode of node.childNodes) {
107
- if (childNode.nodeType === Node.TEXT_NODE) {
108
- return /** @type {Text} */ (childNode);
109
- }
44
+ export function isFocused(element) {
45
+ if (!element) return false;
46
+ if (IS_FIREFOX && element.constructor.formAssociated && element.hasAttribute('disabled')) {
47
+ // https://bugzilla.mozilla.org/show_bug.cgi?id=1818287
48
+ console.warn('Firefox bug 1818287: Disabled form associated custom element cannot receive focus.');
49
+ return false;
110
50
  }
111
- if (!create) return null;
112
- return node.appendChild(document.createTextNode(''));
51
+ if (document.activeElement === element) return true;
52
+ if (!element.isConnected) return false;
53
+ if (element?.getRootNode() === document) return false; // isInLightDOM
54
+ // console.debug('checking shadowdom', element, element.matches(':focus'));
55
+ return element.matches(':focus');
113
56
  }
114
57
 
115
58
  /**
116
- * @param {Node} node
117
- * @param {string} value
118
- * @return {?Text}
59
+ * @param {HTMLElement|Element} element
60
+ * @param {Parameters<HTMLElement['focus']>} [options]
61
+ * @return {boolean} Focus was successful
119
62
  */
120
- export function setTextNode(node, value) {
121
- for (const childNode of node.childNodes) {
122
- if (childNode.nodeType === Node.TEXT_NODE) {
123
- if (value) {
124
- childNode.nodeValue = value;
125
- } else {
126
- node.removeChild(childNode);
127
- }
128
- return /** @type {Text} */ (childNode);
129
- }
63
+ export function attemptFocus(element, ...options) {
64
+ if (!element) return false;
65
+ try {
66
+ // @ts-expect-error Use catch if not HTMLElement
67
+ element.focus(...options);
68
+ } catch (e) {
69
+ console.error(e);
70
+ return false;
71
+ // Ignore error.
130
72
  }
131
- if (!value) return null;
132
- return node.appendChild(document.createTextNode(value));
73
+ return isFocused(element);
133
74
  }
134
75
 
135
76
  /**
136
- * @param {HTMLElement} element
137
- * @param {boolean} [smooth=false]
138
- * @param {boolean} [rtl=false]
139
- * @return {void}
77
+ * @param {Element} element
78
+ * @return {boolean}
140
79
  */
141
- export function scrollToElement(element, smooth, rtl) {
142
- if (!element) {
143
- return;
144
- }
145
- const parent = element.parentElement;
146
- if (!parent) {
147
- return;
148
- }
149
-
150
- let targetScrollLeft = rtl
151
- ? parent.scrollWidth + element.offsetLeft - element.offsetWidth
152
- : element.offsetLeft;
153
-
154
- const elementRect = element.getBoundingClientRect();
155
- const parentRect = parent.getBoundingClientRect();
156
- let subPixelScrollPosition = elementRect.left - parentRect.left;
157
- if (subPixelScrollPosition < 0) {
158
- subPixelScrollPosition = 0;
159
- }
160
- if (Math.abs(subPixelScrollPosition - targetScrollLeft) < 2) {
161
- targetScrollLeft = subPixelScrollPosition;
162
- }
163
- if (parent.scrollLeft === targetScrollLeft) {
164
- return;
165
- }
166
-
167
- if (parent.scrollTo) {
168
- parent.scrollTo({
169
- top: 0,
170
- left: targetScrollLeft,
171
- behavior: smooth ? 'smooth' : 'auto',
172
- });
173
- return;
174
- }
175
- parent.style.setProperty('scroll-behavior', 'auto');
176
- parent.scrollLeft = targetScrollLeft;
177
- requestAnimationFrame(() => {
178
- parent.style.removeProperty('scroll-behavior');
179
- });
80
+ export function isRtl(element) {
81
+ return getComputedStyle(element).direction === 'rtl';
180
82
  }
@@ -0,0 +1,40 @@
1
+ const PREFIX = '_mdw-';
2
+
3
+ /** @type {Set<string>} */
4
+ const generatedUIDs = new Set();
5
+
6
+ /** @return {string} */
7
+ export function generateUID() {
8
+ const id = Math.random().toString(36).slice(2, 10);
9
+ if (generatedUIDs.has(id)) {
10
+ return generateUID();
11
+ }
12
+ generatedUIDs.add(id);
13
+ return id;
14
+ }
15
+
16
+ /**
17
+ * @param {Element} element
18
+ * @param {boolean} [mutate=false]
19
+ * @return {string}
20
+ */
21
+ export function identifierFromElement(element, mutate) {
22
+ if (element.id) {
23
+ return element.id;
24
+ }
25
+ if (!mutate) {
26
+ return null;
27
+ }
28
+ const id = PREFIX + generateUID();
29
+ element.id = id;
30
+ return id;
31
+ }
32
+
33
+ /**
34
+ * @param {string} identifier
35
+ * @param {Element} element
36
+ * @return {boolean}
37
+ */
38
+ export function identifierMatchesElement(identifier, element) {
39
+ return element.id === identifier;
40
+ }
@@ -0,0 +1,410 @@
1
+ import { buildMergePatch, hasMergePatch } from '../utils/jsonMergePatch.js';
2
+
3
+ import { attrNameFromPropName } from './dom.js';
4
+
5
+ /** @typedef {import('./typings.js').ObserverPropertyType} ObserverPropertyType */
6
+
7
+ /** @return {null} */
8
+ const DEFAULT_NULL_PARSER = () => null;
9
+
10
+ /**
11
+ * @see https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Boolean#boolean_coercion
12
+ * @param {any} v
13
+ * @return {boolean}
14
+ */
15
+ const DEFAULT_BOOLEAN_PARSER = (v) => !!v;
16
+
17
+ /**
18
+ * Doesn't support `BigInt` types
19
+ * @see https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Number#number_coercion
20
+ * @param {any} v
21
+ * @return {number}
22
+ */
23
+ const DEFAULT_NUMBER_PARSER = (v) => +v;
24
+
25
+ /**
26
+ * Doesn't support `Symbol` types
27
+ * @see https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String#string_coercion
28
+ * @param {any} v
29
+ * @return {string}
30
+ */
31
+ const DEFAULT_STRING_PARSER = (v) => `${v}`;
32
+
33
+ /**
34
+ * @template T
35
+ * @param {T} o
36
+ * @return {T}
37
+ */
38
+ const DEFAULT_OBJECT_PARSER = (o) => o;
39
+
40
+ /**
41
+ * @template T
42
+ * @param {T} a
43
+ * @param {T} b
44
+ * @return {boolean} true if equal
45
+ */
46
+ export const DEFAULT_OBJECT_COMPARATOR = (a, b) => !hasMergePatch(a, b);
47
+
48
+ /**
49
+ * @template T
50
+ * @param {T} a
51
+ * @param {T} b
52
+ * @return {boolean} true if equal
53
+ */
54
+ export const DEFAULT_OBJECT_DIFF = (a, b) => buildMergePatch(a, b, 'object');
55
+
56
+ /**
57
+ * @param {ObserverPropertyType} type
58
+ * @return {any}
59
+ */
60
+ function emptyFromType(type) {
61
+ switch (type) {
62
+ case 'boolean':
63
+ return false;
64
+ case 'integer':
65
+ case 'float':
66
+ return 0;
67
+ case 'map':
68
+ return new Map();
69
+ case 'set':
70
+ return new Set();
71
+ case 'array':
72
+ return [];
73
+ case 'object':
74
+ return null;
75
+ default:
76
+ case 'string':
77
+ return '';
78
+ }
79
+ }
80
+
81
+ /**
82
+ * @param {ObserverPropertyType} type
83
+ * @return {any}
84
+ */
85
+ function defaultParserFromType(type) {
86
+ switch (type) {
87
+ case 'boolean':
88
+ return DEFAULT_BOOLEAN_PARSER;
89
+ case 'integer':
90
+ // Calls ToNumber(x)
91
+ return Math.round;
92
+ case 'float':
93
+ return DEFAULT_NUMBER_PARSER;
94
+ case 'map':
95
+ return Map;
96
+ case 'set':
97
+ return Set;
98
+ case 'object':
99
+ return DEFAULT_OBJECT_PARSER;
100
+ case 'array':
101
+ return Array.from;
102
+ default:
103
+ case 'string':
104
+ return DEFAULT_STRING_PARSER;
105
+ }
106
+ }
107
+
108
+ /**
109
+ * @template {string} K
110
+ * @template {ObserverPropertyType} [T1=any]
111
+ * @template {any} [T2=import('./typings.js').ParsedObserverPropertyType<T1>]
112
+ * @param {K} name
113
+ * @param {T1|import('./typings.js').ObserverOptions<T1,T2>} [typeOrOptions='string']
114
+ * @param {any} object
115
+ * @return {import('./typings.js').ObserverConfiguration<T1,T2,K> & import('./typings.js').ObserverOptions<T1,T2>}
116
+ */
117
+ export function parseObserverOptions(name, typeOrOptions, object) {
118
+ /** @type {Partial<import('./typings.js').ObserverOptions<T1,T2>>} */
119
+ const options = {
120
+ ...((typeof typeOrOptions === 'string') ? { type: typeOrOptions } : typeOrOptions),
121
+ };
122
+
123
+ let { enumerable, attr, reflect } = options;
124
+ const { type, empty, changedCallback } = options;
125
+
126
+ /** @type {ObserverPropertyType} */
127
+ let parsedType = type;
128
+ if (parsedType == null) {
129
+ // Use .value or .get() to parse type
130
+ const value = options.value ?? empty ?? options.get?.call(object ?? {}, object ?? {});
131
+ if (value == null) {
132
+ parsedType = 'string';
133
+ } else {
134
+ const parsed = typeof value;
135
+ parsedType = (parsed === 'number')
136
+ ? (Number.isInteger(value) ? 'integer' : 'number')
137
+ : parsed;
138
+ }
139
+ }
140
+
141
+ enumerable ??= name[0] !== '_';
142
+ reflect ??= enumerable ? parsedType !== 'object' : (attr ? 'write' : false);
143
+ attr ??= (reflect ? attrNameFromPropName(name) : null);
144
+
145
+ // if defined ? value
146
+ // else if boolean ? false
147
+ // else if onNullish ? false
148
+ // else if empty == null
149
+ const parser = options.parser ?? defaultParserFromType(parsedType);
150
+ let nullParser = options.nullParser;
151
+ let parsedEmpty = empty ?? null;
152
+ if (!nullParser) {
153
+ const nullable = options.nullable ?? (
154
+ parsedType === 'boolean'
155
+ ? false
156
+ : (empty == null));
157
+ if (nullable) {
158
+ nullParser = DEFAULT_NULL_PARSER;
159
+ } else {
160
+ parsedEmpty ??= emptyFromType(parsedType);
161
+ nullParser = parsedEmpty === null ? () => emptyFromType(parsedType) : () => parsedEmpty;
162
+ }
163
+ }
164
+
165
+ let isFn = options.is;
166
+ if (!isFn) {
167
+ isFn = parsedType === 'object'
168
+ ? DEFAULT_OBJECT_COMPARATOR
169
+ : Object.is;
170
+ }
171
+
172
+ const diff = 'diff' in options
173
+ ? options.diff
174
+ : ((parsedType === 'object') ? DEFAULT_OBJECT_DIFF : null);
175
+
176
+ return {
177
+ ...options,
178
+ type: parsedType,
179
+ is: isFn,
180
+ diff,
181
+ attr,
182
+ reflect,
183
+ readonly: options.readonly ?? false,
184
+ enumerable,
185
+ value: options.value ?? parsedEmpty,
186
+ parser,
187
+ nullParser,
188
+ key: name,
189
+ changedCallback,
190
+ watchers: options.watchers ?? [],
191
+ values: options.values ?? new WeakMap(),
192
+ validValues: options.validValues ?? new WeakMap(),
193
+ attributeChangedCallback: options.attributeChangedCallback,
194
+ };
195
+ }
196
+
197
+ const INIT_SYMBOL = Symbol('PROP_INIT');
198
+
199
+ /** @type {Partial<import('./typings.js').ObserverConfiguration<?,?,?>>} */
200
+ const DEFAULT_OBSERVER_CONFIGURATION = {
201
+ nullParser: DEFAULT_NULL_PARSER,
202
+ is: Object.is,
203
+ INIT_SYMBOL,
204
+ };
205
+
206
+ /**
207
+ * @this {import('./typings.js').ObserverConfiguration<?,?,?>}
208
+ * @param {*} value
209
+ */
210
+ export function parsePropertyValue(value) {
211
+ let newValue = value;
212
+ newValue = value == null
213
+ ? this.nullParser.call(this, value)
214
+ : this.parser.call(this, newValue);
215
+ }
216
+
217
+ /**
218
+ * @param {(data: Partial<any>) => any} fn
219
+ * @param {any} arg0
220
+ * @param {any} args[]
221
+ * @param {...any} args
222
+ * @this {any}
223
+ * @return {{props:Set<string>, defaultValue:any, reusable: boolean}}
224
+ */
225
+ export function observeFunction(fn, arg0, ...args) {
226
+ const argPoked = new Set();
227
+ const thisPoked = new Set();
228
+
229
+ /**
230
+ * @template {Object} T
231
+ * @param {T} proxyTarget
232
+ * @param {Set<string>} set
233
+ * @param {string} [prefix]
234
+ * @return {T}
235
+ */
236
+ function buildProxy(proxyTarget, set, prefix) {
237
+ return new Proxy(proxyTarget, {
238
+ get(target, p) {
239
+ const arg = prefix ? `${prefix}.${p}` : p;
240
+ set.add(arg);
241
+ const value = Reflect.get(target, p);
242
+ if (typeof value === 'object' && value != null) {
243
+ console.debug('tried to arg poke object get', p, value);
244
+ return buildProxy(value, set, arg);
245
+ }
246
+ return value;
247
+ },
248
+ has(target, p) {
249
+ const arg = prefix ? `${prefix}.p` : p;
250
+ set.add(arg);
251
+ const value = Reflect.has(target, p);
252
+ return value;
253
+ },
254
+ });
255
+ }
256
+
257
+ const argProxy = buildProxy(arg0, argPoked);
258
+ const thisProxy = buildProxy(this ?? arg0, thisPoked);
259
+ const defaultValue = fn.call(thisProxy, argProxy, ...args);
260
+ /* Arrow functions can reused if they don't poke `this` */
261
+ const reusable = fn.name ? true : !thisPoked.size;
262
+
263
+ const props = new Set([
264
+ ...argPoked,
265
+ ...thisPoked,
266
+ ]);
267
+
268
+ return {
269
+ props,
270
+ defaultValue,
271
+ reusable,
272
+ };
273
+ }
274
+
275
+ /**
276
+ * @template {ObserverPropertyType} T1
277
+ * @template {any} T2
278
+ * @template {string} K
279
+ * @template [C=any]
280
+ * @param {C} object
281
+ * @param {K} key
282
+ * @param {import('./typings.js').ObserverOptions<T1, T2, C>} options
283
+ * @return {import('./typings.js').ObserverConfiguration<T1,T2,K,C>}
284
+ */
285
+ export function defineObservableProperty(object, key, options) {
286
+ /** @type {import('./typings.js').ObserverConfiguration<T1,T2,K,C>} */
287
+ const config = {
288
+ ...DEFAULT_OBSERVER_CONFIGURATION,
289
+ ...parseObserverOptions(key, options, object),
290
+ changedCallback: options.changedCallback,
291
+ };
292
+
293
+ /**
294
+ * @param {T2} oldValue
295
+ * @param {T2} value
296
+ * @param {boolean} [commit=false]
297
+ * @return {boolean} changed
298
+ */
299
+ function detectChange(oldValue, value, commit) {
300
+ if (oldValue === value) return false;
301
+ if (config.get) {
302
+ // TODO: Custom getter vs parser
303
+ }
304
+ let newValue = value;
305
+ newValue = (value == null)
306
+ ? config.nullParser.call(this, value)
307
+ : config.parser.call(this, newValue);
308
+
309
+ let changes = newValue;
310
+ if (oldValue == null) {
311
+ if (newValue == null) return false; // Both nullish
312
+ } else if (newValue != null) {
313
+ if (oldValue === newValue) return false;
314
+ if (config.diff) {
315
+ changes = config.diff.call(this, oldValue, newValue);
316
+ if (changes == null) return false;
317
+ }
318
+ if (config.is.call(this, oldValue, newValue)) return false;
319
+ }
320
+
321
+ // Before changing, store old values of properties that will invalidate;
322
+
323
+ // Do no set if transient (getter)
324
+
325
+ config.values.set(this, newValue);
326
+ // console.log(key, 'value.set', newValue);
327
+ config.propChangedCallback?.call(this, key, oldValue, newValue, changes);
328
+ config.changedCallback?.call(this, oldValue, newValue, changes);
329
+ return true;
330
+ }
331
+ /**
332
+ * @this {C}
333
+ * @return {T2}
334
+ */
335
+ function internalGet() {
336
+ return config.values.has(this) ? config.values.get(this) : config.value;
337
+ }
338
+
339
+ /**
340
+ * @this {C}
341
+ * @param {T2} value
342
+ * @return {void}
343
+ */
344
+ function internalSet(value) {
345
+ const oldValue = this[key];
346
+ // console.log(key, 'internalSet', oldValue, '=>', value);
347
+ detectChange.call(this, oldValue, value, true);
348
+ }
349
+
350
+ /**
351
+ *
352
+ */
353
+ function onInvalidate() {
354
+ // console.log(key, 'onInvalidate', '???');
355
+ const oldValue = config.validValues.get(this);
356
+ const newValue = this[key];
357
+ // console.log(key, 'onInvalidate', oldValue, '=>', newValue);
358
+ detectChange.call(this, oldValue, newValue);
359
+ }
360
+
361
+ if (config.get) {
362
+ const { props } = observeFunction(config.get.bind(object), object, internalGet.bind(object));
363
+ // Set of watchers needed
364
+ // console.log(key, 'invalidates with', props);
365
+ config.watchers.push(
366
+ ...[...props].map((prop) => [prop, onInvalidate]),
367
+ );
368
+ }
369
+ /** @type {Partial<PropertyDescriptor>} */
370
+ const descriptor = {
371
+ enumerable: config.enumerable,
372
+ /**
373
+ * @this {C}
374
+ * @return {T2}
375
+ */
376
+ get() {
377
+ if (config.get) {
378
+ const newValue = config.get.call(this, this, internalGet.bind(this));
379
+ // Store value internally. Used by onInvalidate to get previous value
380
+ config.validValues.set(this, newValue);
381
+ return newValue;
382
+ }
383
+ return internalGet.call(this);
384
+ },
385
+ /**
386
+ * @this {C}
387
+ * @param {T2} value
388
+ * @return {void}
389
+ */
390
+ set(value) {
391
+ if (value === INIT_SYMBOL) {
392
+ // console.log(key, 'returning due to INIT');
393
+ return;
394
+ }
395
+ if (config.set) {
396
+ const oldValue = this[key];
397
+ config.set.call(this, value, internalSet.bind(this));
398
+ const newValue = this[key];
399
+ // Invalidate self
400
+ detectChange.call(this, oldValue, newValue);
401
+ } else {
402
+ internalSet.call(this, value);
403
+ }
404
+ },
405
+ };
406
+
407
+ Object.defineProperty(object, key, descriptor);
408
+
409
+ return config;
410
+ }