flet-box 1.0.6 → 1.0.8

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 (162) hide show
  1. package/README.md +28 -1
  2. package/bin/cli.js +90 -11
  3. package/bin/commands/auditFix.js +682 -0
  4. package/bin/commands/checkApi.js +20 -6
  5. package/bin/commands/checkUi.js +1369 -0
  6. package/bin/commands/create.js +86 -12
  7. package/bin/commands/createBundle.js +75 -1
  8. package/bin/commands/images.js +349 -0
  9. package/bin/commands/pruneAssets.js +170 -0
  10. package/bin/commands/release.js +34 -1
  11. package/bin/commands/runCloudflare.js +47 -9
  12. package/bin/commands/runServer.js +91 -25
  13. package/bin/commands/toPng.js +346 -0
  14. package/bin/commands/unpack.js +1173 -0
  15. package/bin/ota/loader.js +90 -0
  16. package/bin/utils/appSources.js +101 -0
  17. package/bin/utils/bundleConfig.js +166 -0
  18. package/bin/utils/dtsProps.js +147 -0
  19. package/bin/utils/imageTools.js +271 -0
  20. package/bin/utils/images/bmp.js +99 -0
  21. package/bin/utils/images/gif.js +244 -0
  22. package/bin/utils/images/index.js +163 -0
  23. package/bin/utils/images/jpeg.js +643 -0
  24. package/bin/utils/images/png.js +486 -0
  25. package/bin/utils/images/unsupported.js +29 -0
  26. package/bin/utils/neutralise.js +109 -6
  27. package/bin/utils/pwaShell.js +137 -0
  28. package/bin/utils/templates.js +1653 -471
  29. package/docs/README.md +2 -0
  30. package/docs/cli/README.md +144 -1
  31. package/docs/guides/README.md +2 -0
  32. package/docs/guides/clean-ui.md +211 -0
  33. package/docs/guides/minification-and-protection.md +1 -1
  34. package/docs/guides/online-updates.md +105 -9
  35. package/docs/tools/README.md +1 -1
  36. package/docs/tools/animation.md +1 -1
  37. package/docs/tools/markdown.md +3 -3
  38. package/docs/tools/theme.md +41 -1
  39. package/docs/widget/Accordion.md +4 -0
  40. package/docs/widget/AdMob.md +5 -1
  41. package/docs/widget/AdSense.md +4 -0
  42. package/docs/widget/AnimatedBox.md +7 -3
  43. package/docs/widget/AnimatedText.md +4 -0
  44. package/docs/widget/Audio.md +5 -1
  45. package/docs/widget/Avatar.md +15 -3
  46. package/docs/widget/Badge.md +4 -0
  47. package/docs/widget/Button.md +4 -0
  48. package/docs/widget/COMMON_PROPS.md +52 -0
  49. package/docs/widget/Card.md +4 -0
  50. package/docs/widget/Carousel.md +4 -0
  51. package/docs/widget/Chart.md +4 -0
  52. package/docs/widget/Checkbox.md +4 -0
  53. package/docs/widget/Chip.md +4 -0
  54. package/docs/widget/CircularBar.md +4 -0
  55. package/docs/widget/CircularChart.md +4 -0
  56. package/docs/widget/CodeViewer.md +4 -0
  57. package/docs/widget/Column.md +4 -0
  58. package/docs/widget/Container.md +4 -0
  59. package/docs/widget/DataTable.md +4 -0
  60. package/docs/widget/Divider.md +4 -0
  61. package/docs/widget/DraggBox.md +6 -2
  62. package/docs/widget/Dropdown.md +6 -0
  63. package/docs/widget/DroppBox.md +5 -1
  64. package/docs/widget/FloatingActionButton.md +4 -0
  65. package/docs/widget/GridView.md +4 -0
  66. package/docs/widget/Icon.md +4 -0
  67. package/docs/widget/Image.md +14 -3
  68. package/docs/widget/Input.md +4 -0
  69. package/docs/widget/Inspector.md +2 -2
  70. package/docs/widget/InstallButton.md +4 -0
  71. package/docs/widget/ListTile.md +4 -0
  72. package/docs/widget/ListView.md +4 -0
  73. package/docs/widget/Maps.md +191 -0
  74. package/docs/widget/Markdown.md +4 -0
  75. package/docs/widget/MatrixRain.md +4 -0
  76. package/docs/widget/Pagination.md +4 -0
  77. package/docs/widget/ParallaxBox.md +4 -0
  78. package/docs/widget/ProgressBar.md +4 -0
  79. package/docs/widget/QRCode.md +4 -0
  80. package/docs/widget/README.md +12 -10
  81. package/docs/widget/Radio.md +5 -1
  82. package/docs/widget/Rating.md +4 -0
  83. package/docs/widget/Row.md +4 -0
  84. package/docs/widget/Skeleton.md +4 -0
  85. package/docs/widget/Slider.md +4 -0
  86. package/docs/widget/Stack.md +4 -0
  87. package/docs/widget/Stepper.md +4 -0
  88. package/docs/widget/Switch.md +4 -0
  89. package/docs/widget/Tabs.md +5 -5
  90. package/docs/widget/Text.md +4 -0
  91. package/docs/widget/Tooltip.md +14 -13
  92. package/docs/widget/TreeView.md +4 -0
  93. package/docs/widget/Video.md +6 -2
  94. package/package.json +2 -2
  95. package/src/animations/AnimatedBox.js +4 -1
  96. package/src/animations/MatrixRain.js +3 -3
  97. package/src/core/hmr-client.js +129 -34
  98. package/src/index.d.ts +195 -7
  99. package/src/index.js +2 -0
  100. package/src/navigations/AppBar.js +22 -16
  101. package/src/navigations/BottomNavigation.js +8 -13
  102. package/src/navigations/CollapsibleSideBar.js +30 -8
  103. package/src/navigations/Drawer.js +25 -15
  104. package/src/navigations/DrawerItem.js +3 -1
  105. package/src/navigations/Scaffold.js +26 -12
  106. package/src/navigations/Tabs.js +104 -59
  107. package/src/tools/color.js +54 -0
  108. package/src/tools/index.js +9 -1
  109. package/src/tools/scale.js +41 -0
  110. package/src/tools/shadow.js +20 -0
  111. package/src/utils/index.js +1 -0
  112. package/src/utils/readableInk.js +19 -0
  113. package/src/utils/syntaxHighlight.js +78 -10
  114. package/src/utils/themes.js +217 -54
  115. package/src/utils/units.js +33 -11
  116. package/src/widget-factory/effects.js +56 -5
  117. package/src/widget-factory/processProps.js +10 -1
  118. package/src/widget-factory/remTool.js +15 -29
  119. package/src/widget-factory/stackPosition.js +18 -3
  120. package/src/widget-factory/translateProps.js +60 -1
  121. package/src/widgets/Accordion.js +20 -23
  122. package/src/widgets/AdMob.js +7 -2
  123. package/src/widgets/Avatar.js +236 -133
  124. package/src/widgets/Badge.js +3 -2
  125. package/src/widgets/BottomSheet.js +14 -13
  126. package/src/widgets/Button.js +69 -30
  127. package/src/widgets/Card.js +6 -2
  128. package/src/widgets/Carousel.js +12 -10
  129. package/src/widgets/Chart.js +28 -5
  130. package/src/widgets/Checkbox.js +76 -18
  131. package/src/widgets/Chip.js +31 -10
  132. package/src/widgets/CircularBar.js +7 -7
  133. package/src/widgets/CircularChart.js +26 -8
  134. package/src/widgets/CodeViewer.js +93 -20
  135. package/src/widgets/Container.js +13 -0
  136. package/src/widgets/DataTable.js +17 -11
  137. package/src/widgets/DraggBox.js +2 -1
  138. package/src/widgets/Dropdown.js +59 -14
  139. package/src/widgets/DroppBox.js +4 -2
  140. package/src/widgets/FloatingActionButton.js +13 -7
  141. package/src/widgets/Icon.js +3 -1
  142. package/src/widgets/Image.js +102 -3
  143. package/src/widgets/Input.js +30 -23
  144. package/src/widgets/Inspector.js +54 -1
  145. package/src/widgets/InstallButton.js +6 -4
  146. package/src/widgets/ListTile.js +4 -3
  147. package/src/widgets/ListView.js +30 -12
  148. package/src/widgets/Maps.js +1495 -0
  149. package/src/widgets/Markdown.js +37 -26
  150. package/src/widgets/Modal.js +14 -11
  151. package/src/widgets/Pagination.js +16 -11
  152. package/src/widgets/ProgressBar.js +6 -4
  153. package/src/widgets/Radio.js +73 -15
  154. package/src/widgets/Rating.js +24 -6
  155. package/src/widgets/Skeleton.js +31 -31
  156. package/src/widgets/Slider.js +29 -18
  157. package/src/widgets/SnackBar.js +35 -39
  158. package/src/widgets/Stepper.js +13 -9
  159. package/src/widgets/Switch.js +59 -18
  160. package/src/widgets/Tooltip.js +24 -12
  161. package/src/widgets/TreeView.js +27 -15
  162. package/src/widgets/index.js +1 -0
@@ -45,10 +45,14 @@ Every widget also accepts these shared props — see [common props](COMMON_PROPS
45
45
  | `padding` | `Padding` | Space inside the widget, between its content and its border. |
46
46
  | `margin` | `Margin` | Space outside the widget, between it and its neighbors. |
47
47
  | `bgColor` | `Color` | Background color. Alias: `backgroundColor`. |
48
+ | `backgroundColor` | `Color` | Background color. Alias of `bgColor`. |
48
49
  | `color` | `Color` | Foreground color, usually the text or icon color. |
49
50
  | `borderRadius` | `number \| string` | Rounds the corners of the widget. |
50
51
  | `elevation` | `number` | Shadow depth. Higher values lift the widget off the page. |
51
52
  | `shadow` | `string` | Raw CSS `box-shadow` value, for a custom shadow. |
53
+ | `filter` | `string` | Raw CSS `filter` value applied to the widget itself, e.g. `blur(4px)`. |
54
+ | `backdropFilter` | `string` | Raw CSS `backdrop-filter` value: what sits behind the widget is blurred through it, which is what makes a translucent card frosted glass. |
55
+ | `maskImage` | `string` | Raw CSS `mask-image` value, used to fade a widget out at its edges instead of cutting it. |
52
56
  | `opacity` | `number` | Opacity from 0 (invisible) to 1 (fully opaque). |
53
57
  | `visible` | `boolean` | Whether the widget is rendered and visible. |
54
58
  | `disabled` | `boolean` | Disables interaction and shows the non-interactive state. |
@@ -48,10 +48,14 @@ Every widget also accepts these shared props — see [common props](COMMON_PROPS
48
48
  | `padding` | `Padding` | Space inside the widget, between its content and its border. |
49
49
  | `margin` | `Margin` | Space outside the widget, between it and its neighbors. |
50
50
  | `bgColor` | `Color` | Background color. Alias: `backgroundColor`. |
51
+ | `backgroundColor` | `Color` | Background color. Alias of `bgColor`. |
51
52
  | `color` | `Color` | Foreground color, usually the text or icon color. |
52
53
  | `borderRadius` | `number \| string` | Rounds the corners of the widget. |
53
54
  | `elevation` | `number` | Shadow depth. Higher values lift the widget off the page. |
54
55
  | `shadow` | `string` | Raw CSS `box-shadow` value, for a custom shadow. |
56
+ | `filter` | `string` | Raw CSS `filter` value applied to the widget itself, e.g. `blur(4px)`. |
57
+ | `backdropFilter` | `string` | Raw CSS `backdrop-filter` value: what sits behind the widget is blurred through it, which is what makes a translucent card frosted glass. |
58
+ | `maskImage` | `string` | Raw CSS `mask-image` value, used to fade a widget out at its edges instead of cutting it. |
55
59
  | `opacity` | `number` | Opacity from 0 (invisible) to 1 (fully opaque). |
56
60
  | `visible` | `boolean` | Whether the widget is rendered and visible. |
57
61
  | `disabled` | `boolean` | Disables interaction and shows the non-interactive state. |
@@ -59,10 +59,14 @@ Every widget also accepts these shared props — see [common props](COMMON_PROPS
59
59
  | `padding` | `Padding` | Space inside the widget, between its content and its border. |
60
60
  | `margin` | `Margin` | Space outside the widget, between it and its neighbors. |
61
61
  | `bgColor` | `Color` | Background color. Alias: `backgroundColor`. |
62
+ | `backgroundColor` | `Color` | Background color. Alias of `bgColor`. |
62
63
  | `color` | `Color` | Foreground color, usually the text or icon color. |
63
64
  | `borderRadius` | `number \| string` | Rounds the corners of the widget. |
64
65
  | `elevation` | `number` | Shadow depth. Higher values lift the widget off the page. |
65
66
  | `shadow` | `string` | Raw CSS `box-shadow` value, for a custom shadow. |
67
+ | `filter` | `string` | Raw CSS `filter` value applied to the widget itself, e.g. `blur(4px)`. |
68
+ | `backdropFilter` | `string` | Raw CSS `backdrop-filter` value: what sits behind the widget is blurred through it, which is what makes a translucent card frosted glass. |
69
+ | `maskImage` | `string` | Raw CSS `mask-image` value, used to fade a widget out at its edges instead of cutting it. |
66
70
  | `opacity` | `number` | Opacity from 0 (invisible) to 1 (fully opaque). |
67
71
  | `visible` | `boolean` | Whether the widget is rendered and visible. |
68
72
  | `disabled` | `boolean` | Disables interaction and shows the non-interactive state. |
@@ -41,10 +41,14 @@ Every widget also accepts these shared props — see [common props](COMMON_PROPS
41
41
  | `padding` | `Padding` | Space inside the widget, between its content and its border. |
42
42
  | `margin` | `Margin` | Space outside the widget, between it and its neighbors. |
43
43
  | `bgColor` | `Color` | Background color. Alias: `backgroundColor`. |
44
+ | `backgroundColor` | `Color` | Background color. Alias of `bgColor`. |
44
45
  | `color` | `Color` | Foreground color, usually the text or icon color. |
45
46
  | `borderRadius` | `number \| string` | Rounds the corners of the widget. |
46
47
  | `elevation` | `number` | Shadow depth. Higher values lift the widget off the page. |
47
48
  | `shadow` | `string` | Raw CSS `box-shadow` value, for a custom shadow. |
49
+ | `filter` | `string` | Raw CSS `filter` value applied to the widget itself, e.g. `blur(4px)`. |
50
+ | `backdropFilter` | `string` | Raw CSS `backdrop-filter` value: what sits behind the widget is blurred through it, which is what makes a translucent card frosted glass. |
51
+ | `maskImage` | `string` | Raw CSS `mask-image` value, used to fade a widget out at its edges instead of cutting it. |
48
52
  | `opacity` | `number` | Opacity from 0 (invisible) to 1 (fully opaque). |
49
53
  | `visible` | `boolean` | Whether the widget is rendered and visible. |
50
54
  | `disabled` | `boolean` | Disables interaction and shows the non-interactive state. |
@@ -58,10 +58,14 @@ Every widget also accepts these shared props — see [common props](COMMON_PROPS
58
58
  | `padding` | `Padding` | Space inside the widget, between its content and its border. |
59
59
  | `margin` | `Margin` | Space outside the widget, between it and its neighbors. |
60
60
  | `bgColor` | `Color` | Background color. Alias: `backgroundColor`. |
61
+ | `backgroundColor` | `Color` | Background color. Alias of `bgColor`. |
61
62
  | `color` | `Color` | Foreground color, usually the text or icon color. |
62
63
  | `borderRadius` | `number \| string` | Rounds the corners of the widget. |
63
64
  | `elevation` | `number` | Shadow depth. Higher values lift the widget off the page. |
64
65
  | `shadow` | `string` | Raw CSS `box-shadow` value, for a custom shadow. |
66
+ | `filter` | `string` | Raw CSS `filter` value applied to the widget itself, e.g. `blur(4px)`. |
67
+ | `backdropFilter` | `string` | Raw CSS `backdrop-filter` value: what sits behind the widget is blurred through it, which is what makes a translucent card frosted glass. |
68
+ | `maskImage` | `string` | Raw CSS `mask-image` value, used to fade a widget out at its edges instead of cutting it. |
65
69
  | `opacity` | `number` | Opacity from 0 (invisible) to 1 (fully opaque). |
66
70
  | `visible` | `boolean` | Whether the widget is rendered and visible. |
67
71
  | `disabled` | `boolean` | Disables interaction and shows the non-interactive state. |
@@ -41,10 +41,14 @@ Every widget also accepts these shared props — see [common props](COMMON_PROPS
41
41
  | `padding` | `Padding` | Space inside the widget, between its content and its border. |
42
42
  | `margin` | `Margin` | Space outside the widget, between it and its neighbors. |
43
43
  | `bgColor` | `Color` | Background color. Alias: `backgroundColor`. |
44
+ | `backgroundColor` | `Color` | Background color. Alias of `bgColor`. |
44
45
  | `color` | `Color` | Foreground color, usually the text or icon color. |
45
46
  | `borderRadius` | `number \| string` | Rounds the corners of the widget. |
46
47
  | `elevation` | `number` | Shadow depth. Higher values lift the widget off the page. |
47
48
  | `shadow` | `string` | Raw CSS `box-shadow` value, for a custom shadow. |
49
+ | `filter` | `string` | Raw CSS `filter` value applied to the widget itself, e.g. `blur(4px)`. |
50
+ | `backdropFilter` | `string` | Raw CSS `backdrop-filter` value: what sits behind the widget is blurred through it, which is what makes a translucent card frosted glass. |
51
+ | `maskImage` | `string` | Raw CSS `mask-image` value, used to fade a widget out at its edges instead of cutting it. |
48
52
  | `opacity` | `number` | Opacity from 0 (invisible) to 1 (fully opaque). |
49
53
  | `visible` | `boolean` | Whether the widget is rendered and visible. |
50
54
  | `disabled` | `boolean` | Disables interaction and shows the non-interactive state. |
@@ -39,19 +39,19 @@ Tabs({
39
39
  | `onChange` | function | — | Fired with the new index when the tab changes. |
40
40
  | `variant` | `'underline'`/`'filled'`/`'slider'`/`'pills'` | `'underline'` | Visual treatment of the tab bar. |
41
41
  | `size` | `'small'`/`'medium'`/`'large'` | `'medium'` | Font, padding, icon, and height presets. |
42
- | `textColor` | Color | `colors.text` | Inactive label/icon color. |
43
- | `activeTextColor` | Color | `colors.white` | Active label/icon color. |
42
+ | `textColor` | Color | `colors.textSecondary` | Inactive label/icon color. |
43
+ | `activeTextColor` | Color | ink on `slider`, `colors.text` otherwise | Active label/icon color. |
44
44
  | `bgColor` | Color | `colors.gray100` | Bar background for `slider`/`filled` variants. |
45
- | `buttonColor` | Color | `colors.secondary` | Background of the `slider` indicator and `pills`. |
45
+ | `buttonColor` | Color | `color` | Background of the `slider` indicator. |
46
46
  | `dividerColor` | Color | `colors.border` | Bottom border for the `underline` variant (when `showDivider`). |
47
47
  | `fullWidth` | boolean | `true` | Tabs share the full width; otherwise they hug their content. |
48
48
  | `showDivider` | boolean | `true` | Bottom divider under an `underline` bar. |
49
49
  | `showIcon` | boolean | `false` | Show the per-tab `icon`. |
50
- | `iconPosition` | `'left'`/`'right'`/`'top'`/`'bottom'` | `'left'` | Where the icon sits: `'left'` places it before the label; any other value places it after. |
50
+ | `iconPosition` | `'left'`/`'right'`/`'top'`/`'bottom'` | `'left'` | Where the icon sits: `'left'` before the label, `'right'` after it, `'top'`/`'bottom'` stacked above/below the label row. |
51
51
  | `iconSize` | number | `18` | Icon size in pixels. |
52
52
  | `badges` | array | `[]` | Badge values per tab (`badges[i]`), or set them inline via `{ badge }`. |
53
53
  | `alignment` | `'left'`/`'center'`/`'right'` | `'left'` | Accepted for API compatibility; currently has no visual effect. |
54
- | `color` | Color | `colors.primary` | Accepted for API compatibility; active styling uses `activeTextColor`/`buttonColor` instead. |
54
+ | `color` | Color | `colors.primary` | Accent: the `underline` indicator, the `pills` tint, and the default `buttonColor`. |
55
55
 
56
56
  These are the props specific to `Tabs`. It also accepts every [common prop](COMMON_PROPS.md).
57
57
 
@@ -49,10 +49,14 @@ Every widget also accepts these shared props — see [common props](COMMON_PROPS
49
49
  | `padding` | `Padding` | Space inside the widget, between its content and its border. |
50
50
  | `margin` | `Margin` | Space outside the widget, between it and its neighbors. |
51
51
  | `bgColor` | `Color` | Background color. Alias: `backgroundColor`. |
52
+ | `backgroundColor` | `Color` | Background color. Alias of `bgColor`. |
52
53
  | `color` | `Color` | Foreground color, usually the text or icon color. |
53
54
  | `borderRadius` | `number \| string` | Rounds the corners of the widget. |
54
55
  | `elevation` | `number` | Shadow depth. Higher values lift the widget off the page. |
55
56
  | `shadow` | `string` | Raw CSS `box-shadow` value, for a custom shadow. |
57
+ | `filter` | `string` | Raw CSS `filter` value applied to the widget itself, e.g. `blur(4px)`. |
58
+ | `backdropFilter` | `string` | Raw CSS `backdrop-filter` value: what sits behind the widget is blurred through it, which is what makes a translucent card frosted glass. |
59
+ | `maskImage` | `string` | Raw CSS `mask-image` value, used to fade a widget out at its edges instead of cutting it. |
56
60
  | `opacity` | `number` | Opacity from 0 (invisible) to 1 (fully opaque). |
57
61
  | `visible` | `boolean` | Whether the widget is rendered and visible. |
58
62
  | `disabled` | `boolean` | Disables interaction and shows the non-interactive state. |
@@ -26,7 +26,8 @@ const tip = Tooltip({
26
26
  | `text` | `string` | Visible text content. |
27
27
  | `child` | `Widget` | A single child widget. Alias: `children` for a list. |
28
28
  | `position` | `'top' \| 'bottom' \| 'left' \| 'right'` | CSS `position` value, or `stack` for centered stacking. |
29
- | `delay` | `number` | Delay before the animation starts, in milliseconds. |
29
+ | `delay` | `number` | Milliseconds the pointer has to stay on the widget before the tooltip appears. |
30
+ | `tooltipDelay` | `number` | Deprecated alias of `delay`. |
30
31
  | `bgColor` | `Color` | Background color. Alias: `backgroundColor`. |
31
32
  | `textColor` | `Color` | Color of the button label. |
32
33
  | `fontSize` | `number` | Size of the font. |
@@ -56,10 +57,14 @@ Every widget also accepts these shared props — see [common props](COMMON_PROPS
56
57
  | `padding` | `Padding` | Space inside the widget, between its content and its border. |
57
58
  | `margin` | `Margin` | Space outside the widget, between it and its neighbors. |
58
59
  | `bgColor` | `Color` | Background color. Alias: `backgroundColor`. |
60
+ | `backgroundColor` | `Color` | Background color. Alias of `bgColor`. |
59
61
  | `color` | `Color` | Foreground color, usually the text or icon color. |
60
62
  | `borderRadius` | `number \| string` | Rounds the corners of the widget. |
61
63
  | `elevation` | `number` | Shadow depth. Higher values lift the widget off the page. |
62
64
  | `shadow` | `string` | Raw CSS `box-shadow` value, for a custom shadow. |
65
+ | `filter` | `string` | Raw CSS `filter` value applied to the widget itself, e.g. `blur(4px)`. |
66
+ | `backdropFilter` | `string` | Raw CSS `backdrop-filter` value: what sits behind the widget is blurred through it, which is what makes a translucent card frosted glass. |
67
+ | `maskImage` | `string` | Raw CSS `mask-image` value, used to fade a widget out at its edges instead of cutting it. |
63
68
  | `opacity` | `number` | Opacity from 0 (invisible) to 1 (fully opaque). |
64
69
  | `visible` | `boolean` | Whether the widget is rendered and visible. |
65
70
  | `disabled` | `boolean` | Disables interaction and shows the non-interactive state. |
@@ -109,24 +114,20 @@ const tip = Tooltip({
109
114
 
110
115
  ## Tips
111
116
 
112
- - Attach it to any widget via child; the tooltip is a separate portal, so overflow
113
- - hidden ancestors do not cut it off.
114
- - delay controls how long the pointer must rest before the tooltip appears; lower it
115
- - for dense toolbars, raise it for error-prone hints.
116
- - The bubble is clamped to the viewport edges, so top/left placements can sit slightly
117
- - inside the window bounds.
117
+ - Attach it to any widget via child; the tooltip is a separate portal, so overflow hidden ancestors do not cut it off.
118
+ - delay controls how long the pointer must rest before the tooltip appears; lower it for dense toolbars, raise it for error-prone hints.
119
+ - The bubble is clamped to the viewport edges, so top/left placements can sit slightly inside the window bounds.
118
120
 
119
121
  ## Accessibility
120
122
 
121
- - The wrapped child keeps its focus handlers, so keyboard users tabbing onto it get
122
- - the same tooltip as mouse hover.
123
+ - The wrapped child keeps its focus handlers, so keyboard users tabbing onto it get the same tooltip as mouse hover.
123
124
 
124
125
  ## Behavior
125
126
 
126
- - The tooltip hides itself on window scroll or resize and removes its body portal plus
127
- - listeners on unmount.
128
- - The wrapped child gains showTooltip, hideTooltip, updateContent, and updatePosition
129
- - helpers for imperative control.
127
+ - The tooltip hides itself on window scroll or resize and removes its body portal plus listeners on unmount.
128
+ - The wrapped child gains showTooltip, hideTooltip, updateContent, and updatePosition helpers for imperative control.
129
+ - A pointer that leaves before the wait is over never shows the bubble: leaving clears the timer.
130
+ - tooltipDelay is the old name of delay. When both are given, delay wins.
130
131
 
131
132
  ## Related widgets
132
133
 
@@ -72,10 +72,14 @@ Every widget also accepts these shared props — see [common props](COMMON_PROPS
72
72
  | `padding` | `Padding` | Space inside the widget, between its content and its border. |
73
73
  | `margin` | `Margin` | Space outside the widget, between it and its neighbors. |
74
74
  | `bgColor` | `Color` | Background color. Alias: `backgroundColor`. |
75
+ | `backgroundColor` | `Color` | Background color. Alias of `bgColor`. |
75
76
  | `color` | `Color` | Foreground color, usually the text or icon color. |
76
77
  | `borderRadius` | `number \| string` | Rounds the corners of the widget. |
77
78
  | `elevation` | `number` | Shadow depth. Higher values lift the widget off the page. |
78
79
  | `shadow` | `string` | Raw CSS `box-shadow` value, for a custom shadow. |
80
+ | `filter` | `string` | Raw CSS `filter` value applied to the widget itself, e.g. `blur(4px)`. |
81
+ | `backdropFilter` | `string` | Raw CSS `backdrop-filter` value: what sits behind the widget is blurred through it, which is what makes a translucent card frosted glass. |
82
+ | `maskImage` | `string` | Raw CSS `mask-image` value, used to fade a widget out at its edges instead of cutting it. |
79
83
  | `opacity` | `number` | Opacity from 0 (invisible) to 1 (fully opaque). |
80
84
  | `visible` | `boolean` | Whether the widget is rendered and visible. |
81
85
  | `disabled` | `boolean` | Disables interaction and shows the non-interactive state. |
@@ -44,10 +44,14 @@ Every widget also accepts these shared props — see [common props](COMMON_PROPS
44
44
  | `padding` | `Padding` | Space inside the widget, between its content and its border. |
45
45
  | `margin` | `Margin` | Space outside the widget, between it and its neighbors. |
46
46
  | `bgColor` | `Color` | Background color. Alias: `backgroundColor`. |
47
+ | `backgroundColor` | `Color` | Background color. Alias of `bgColor`. |
47
48
  | `color` | `Color` | Foreground color, usually the text or icon color. |
48
49
  | `borderRadius` | `number \| string` | Rounds the corners of the widget. |
49
50
  | `elevation` | `number` | Shadow depth. Higher values lift the widget off the page. |
50
51
  | `shadow` | `string` | Raw CSS `box-shadow` value, for a custom shadow. |
52
+ | `filter` | `string` | Raw CSS `filter` value applied to the widget itself, e.g. `blur(4px)`. |
53
+ | `backdropFilter` | `string` | Raw CSS `backdrop-filter` value: what sits behind the widget is blurred through it, which is what makes a translucent card frosted glass. |
54
+ | `maskImage` | `string` | Raw CSS `mask-image` value, used to fade a widget out at its edges instead of cutting it. |
51
55
  | `opacity` | `number` | Opacity from 0 (invisible) to 1 (fully opaque). |
52
56
  | `visible` | `boolean` | Whether the widget is rendered and visible. |
53
57
  | `disabled` | `boolean` | Disables interaction and shows the non-interactive state. |
@@ -121,7 +125,7 @@ const clip = Video({
121
125
  ## Continue reading
122
126
 
123
127
  - **Previous:** [Audio](Audio.md)
124
- - **Next:** [DraggBox](DraggBox.md)
128
+ - **Next:** [Maps](Maps.md)
125
129
  - **Index:** [Widget index](README.md) · [Start here](START_HERE.md)
126
130
 
127
- You are reading **Chapter 7 · Media and drag & drop** (2 of 4).
131
+ You are reading **Chapter 7 · Media and drag & drop** (2 of 5).
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "flet-box",
3
- "version": "1.0.6",
3
+ "version": "1.0.8",
4
4
  "description": "Declarative, zero-dependency UI framework in vanilla JS — ship web, PWA, Android and iOS from one codebase",
5
5
  "type": "module",
6
6
  "main": "src/index.js",
@@ -19,7 +19,7 @@
19
19
  "dev": "node bin/cli.js run --hot",
20
20
  "build": "node bin/cli.js createBundle",
21
21
  "release": "node bin/cli.js release",
22
- "test": "node scripts/check-widgets.mjs && node scripts/check-prop-registry.mjs && node scripts/check-docs-props.mjs && node scripts/check-api-surface.mjs && node scripts/check-router-base.mjs && node scripts/check-cli-install.mjs && python3 tools/snippets-creator-flet-box/build_snippets.py --check && node scripts/check-snippets.mjs",
22
+ "test": "node scripts/check-widgets.mjs && node scripts/check-widget-scale.mjs && node scripts/check-prop-registry.mjs && node scripts/check-docs-props.mjs && node scripts/check-api-surface.mjs && node scripts/check-api-propscan.mjs && node scripts/check-router-base.mjs && node scripts/check-clean-ui.mjs && node scripts/check-ota-assets.mjs && node scripts/check-pwa-shell.mjs && node scripts/check-cli-install.mjs && python3 tools/snippets-creator-flet-box/build_snippets.py --check && node scripts/check-snippets.mjs",
23
23
  "test:browser": "node scripts/run-browser-tests.mjs"
24
24
  },
25
25
  "keywords": [
@@ -381,7 +381,10 @@ const generateKeyframes = (animations) => {
381
381
 
382
382
  animations.forEach((anim) => {
383
383
  const effect = effectMap[anim.effect] || anim.effect;
384
- const { from, to, reverse = true } = anim;
384
+ // Straight `from → to` is the default: a one-shot entry animation must hold
385
+ // `to`. Cycling back is opt-in, or every documented `opacity 0 → 1` faded
386
+ // to invisible again at 100%.
387
+ const { from, to, reverse = false } = anim;
385
388
 
386
389
  // A descriptor without `from`/`to` is malformed. Skip it with a warning
387
390
  // rather than throwing a TypeError out of the caller's entire render.
@@ -219,8 +219,9 @@ export const MatrixRain = (props = {}) => {
219
219
  // above), because the canvas has no parent until the caller appends it.
220
220
 
221
221
  /**
222
- * Stops the animation loop, removes event listeners, disconnects the
223
- * ResizeObserver, and removes the canvas from the DOM.
222
+ * Stops the animation loop, removes the window listeners and disconnects the
223
+ * ResizeObserver. The canvas stays where it is: the caller owns the element and
224
+ * decides whether to remove it, which is what the module contract documents.
224
225
  *
225
226
  * @returns {void}
226
227
  */
@@ -228,7 +229,6 @@ export const MatrixRain = (props = {}) => {
228
229
  if (animationId) cancelAnimationFrame(animationId);
229
230
  window.removeEventListener("resize", handleResize);
230
231
  if (resizeObserver) resizeObserver.disconnect();
231
- if (canvas && canvas.parentNode) canvas.parentNode.removeChild(canvas);
232
232
  };
233
233
 
234
234
  // Chain cleanup so any previously assigned _cleanup is also called
@@ -1,4 +1,5 @@
1
1
  // src/core/hmr-client.js
2
+ import { getAllRam, saveRam } from "../services/RamStore.js";
2
3
 
3
4
  /** @type {WebSocket|null} Active WebSocket connection to the HMR server. */
4
5
  let ws = null;
@@ -11,6 +12,83 @@ let ws = null;
11
12
  */
12
13
  let modules = new Map();
13
14
 
15
+ /** sessionStorage key that carries `useState` RAM across a hot reload. */
16
+ const STATE_KEY = "__fletbox_hmr_state";
17
+
18
+ /** How many seconds to keep retrying after the server drops the socket. */
19
+ const MAX_RETRIES = 30;
20
+
21
+ let retries = 0;
22
+ let everOpened = false;
23
+ let retryTimer = null;
24
+
25
+ /**
26
+ * The live state, JSON-safe.
27
+ *
28
+ * `useState` lives in a plain Map, so a value that cannot cross a page reload
29
+ * (a DOM node, a circular graph, a function) is skipped rather than poisoning
30
+ * the whole snapshot.
31
+ *
32
+ * @returns {Object}
33
+ */
34
+ const snapshotRam = () => {
35
+ const snapshot = {};
36
+ for (const [key, value] of Object.entries(getAllRam())) {
37
+ try {
38
+ JSON.stringify(value);
39
+ snapshot[key] = value;
40
+ } catch (e) {
41
+ // Not serialisable: this key starts from its default on the next page.
42
+ }
43
+ }
44
+ return snapshot;
45
+ };
46
+
47
+ /**
48
+ * Reload the page without losing the developer's place: state is written to
49
+ * sessionStorage first and put back by `initHMR` on the next load.
50
+ *
51
+ * @returns {void}
52
+ */
53
+ const reloadKeepingState = () => {
54
+ try {
55
+ sessionStorage.setItem(STATE_KEY, JSON.stringify(snapshotRam()));
56
+ } catch (e) {
57
+ // Private mode, quota, no sessionStorage: reload anyway.
58
+ }
59
+ window.location.reload();
60
+ };
61
+
62
+ /**
63
+ * Push a previous snapshot back into the RAM store.
64
+ *
65
+ * Runs after the app module has already rendered, which is fine: `saveRam`
66
+ * notifies subscribers, so every `useState` binding repaints with the value it
67
+ * had before the reload.
68
+ *
69
+ * @returns {number} keys restored
70
+ */
71
+ const restoreRam = () => {
72
+ let raw = null;
73
+ try {
74
+ raw = sessionStorage.getItem(STATE_KEY);
75
+ } catch (e) {
76
+ return 0;
77
+ }
78
+ if (!raw) return 0;
79
+ let saved;
80
+ try {
81
+ saved = JSON.parse(raw);
82
+ } catch (e) {
83
+ return 0;
84
+ }
85
+ let restored = 0;
86
+ for (const [key, value] of Object.entries(saved)) {
87
+ if (saveRam(key, value)) restored++;
88
+ }
89
+ return restored;
90
+ };
91
+
14
92
  /**
15
93
  * Initialises the Hot Module Replacement (HMR) client.
16
94
  *
@@ -23,19 +101,44 @@ let modules = new Map();
23
101
  * - `hmr` — a file changed; delegates to `handleHMR`.
24
102
  * - `reload` — the server requests a full page reload.
25
103
  *
26
- * On disconnect the client waits 500 ms then reloads the page so the
27
- * developer always sees a fresh state.
104
+ * A dropped socket is retried, not reloaded: reloading into a server that is
105
+ * still restarting (or a tunnel that closed an idle socket) produced an error
106
+ * page and then a reload loop. When the connection *re*-establishes, the code
107
+ * the page runs is stale and the page reloads — with its state.
108
+ *
109
+ * @returns {void}
28
110
  */
29
111
  export const initHMR = () => {
112
+ const restored = restoreRam();
113
+ if (restored) console.log(`♻️ HMR restored ${restored} state key(s)`);
114
+ connect();
115
+ };
116
+
117
+ /**
118
+ * @returns {void}
119
+ */
120
+ const connect = () => {
30
121
  const protocol = location.protocol === "https:" ? "wss:" : "ws:";
31
122
  ws = new WebSocket(`${protocol}//${location.host}`);
32
123
 
33
124
  ws.onopen = () => {
125
+ retries = 0;
126
+ if (everOpened) {
127
+ console.log("🔥 HMR reconnected — the page is stale, reloading");
128
+ reloadKeepingState();
129
+ return;
130
+ }
131
+ everOpened = true;
34
132
  console.log("🔥 HMR connected");
35
133
  };
36
134
 
37
135
  ws.onmessage = (event) => {
38
- const data = JSON.parse(event.data);
136
+ let data;
137
+ try {
138
+ data = JSON.parse(event.data);
139
+ } catch (e) {
140
+ return; // a proxy or tunnel injecting a non-JSON frame must not kill the client
141
+ }
39
142
 
40
143
  if (data.type === "request-modules") {
41
144
  // Send the list of registered module URLs back to the server.
@@ -50,14 +153,19 @@ export const initHMR = () => {
50
153
  }
51
154
 
52
155
  if (data.type === "reload") {
53
- console.log("🔄 Full reload triggered");
54
- window.location.reload();
156
+ console.log("🔄 Reload triggered by the server");
157
+ reloadKeepingState();
55
158
  }
56
159
  };
57
160
 
58
161
  ws.onclose = () => {
59
- console.log("🔄 HMR disconnected, reloading...");
60
- setTimeout(() => window.location.reload(), 500);
162
+ if (retries >= MAX_RETRIES) {
163
+ console.warn("🔌 HMR gave up: the dev server is unreachable. Refresh to retry.");
164
+ return;
165
+ }
166
+ retries++;
167
+ clearTimeout(retryTimer);
168
+ retryTimer = setTimeout(connect, 1000);
61
169
  };
62
170
  };
63
171
 
@@ -68,16 +176,13 @@ export const initHMR = () => {
68
176
  *
69
177
  * - `css` — hot-reloads matching `<link>` stylesheets by appending a cache-
70
178
  * busting timestamp to their `href`, avoiding a full page reload.
71
- * - `exports-changed` — the module's public API changed in a way that cannot
72
- * be patched in-place; triggers a full reload.
73
- * - anything else — re-imports the changed module via a dynamic `import()` and
74
- * dispatches an `hmr:update` CustomEvent so components can react. Falls back
75
- * to a full reload if the import fails.
179
+ * - anything else — the module graph cannot be rebound in place, so the page
180
+ * reloads and the `useState` RAM is restored from the snapshot.
76
181
  *
77
182
  * @param {{ file: string, changeType: string }} data - The HMR payload from the server.
78
183
  * @param {string} data.file - Relative path of the changed file.
79
- * @param {string} data.changeType - The kind of change (`"css"`,
80
- * `"exports-changed"`, or any other string for a JS hot-swap).
184
+ * @param {string} data.changeType - The kind of change (`"css"`, or any other
185
+ * string for a reload with the state kept).
81
186
  */
82
187
  const handleHMR = (data) => {
83
188
  const { file, changeType } = data;
@@ -97,26 +202,16 @@ const handleHMR = (data) => {
97
202
  return;
98
203
  }
99
204
 
100
- if (changeType === "exports-changed") {
101
- console.log(`📦 Exports changed in ${file}, reloading...`);
102
- window.location.reload();
103
- return;
104
- }
105
-
106
- // JS code change — attempt a hot swap via dynamic import.
107
- console.log(`🔥 Hot reloading: ${file}`);
108
- const url = `/${file}?t=${Date.now()}`;
109
- import(url)
110
- .then((module) => {
111
- // Notify any listening components that the module was updated.
112
- window.dispatchEvent(
113
- new CustomEvent("hmr:update", { detail: { file, module } }),
114
- );
115
- })
116
- .catch((err) => {
117
- console.error("HMR import failed:", err);
118
- window.location.reload();
119
- });
205
+ if (changeType === "exports-changed") console.log(`📦 Exports changed in ${file}`);
206
+ // A JS change reloads the page and puts the state back.
207
+ //
208
+ // Re-importing the file is not a swap: a widget that already closed over the
209
+ // old function keeps the old function, and the fresh module instance nobody
210
+ // references changes nothing on screen. What the developer should see is the
211
+ // new code, so the module graph is re-fetched — and because `useState` RAM
212
+ // survives the reload, that is not paid for with the form you were filling.
213
+ console.log(`🔥 Reload with state: ${file}`);
214
+ reloadKeepingState();
120
215
  };
121
216
 
122
217
  /**