flet-box 1.0.3 → 1.0.5
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.
- package/README.md +10 -0
- package/bin/cli.js +15 -0
- package/bin/commands/checkApi.js +761 -0
- package/bin/commands/create.js +77 -5
- package/bin/utils/dtsProps.js +191 -0
- package/bin/utils/moduleExports.js +165 -0
- package/bin/utils/neutralise.js +64 -0
- package/bin/utils/templates.js +366 -27
- package/docs/CONTRIBUTING.md +156 -0
- package/docs/README.md +68 -0
- package/docs/arquitectura.md +164 -0
- package/docs/cli/README.md +542 -0
- package/docs/guides/README.md +33 -0
- package/docs/guides/app-templates.md +197 -0
- package/docs/guides/compatibility.md +95 -0
- package/docs/guides/embedding.md +284 -0
- package/docs/guides/first-app.md +208 -0
- package/docs/guides/frontend-services.md +171 -0
- package/docs/guides/minification-and-protection.md +260 -0
- package/docs/guides/mobile-and-platforms.md +439 -0
- package/docs/guides/online-updates.md +196 -0
- package/docs/guides/router.md +282 -0
- package/docs/guides/state.md +283 -0
- package/docs/guides/syntax-philosophy.md +150 -0
- package/docs/guides/utilities.md +241 -0
- package/docs/guides/widget-structure.md +163 -0
- package/docs/server/README.md +68 -0
- package/docs/server/START_HERE.md +121 -0
- package/docs/server/api.md +225 -0
- package/docs/server/data-services.md +300 -0
- package/docs/server/deployment.md +113 -0
- package/docs/server/security.md +196 -0
- package/docs/services/README.md +79 -0
- package/docs/services/RamStore.md +84 -0
- package/docs/services/Session.md +84 -0
- package/docs/services/Storage.md +88 -0
- package/docs/services/http.md +86 -0
- package/docs/tools/README.md +138 -0
- package/docs/tools/animation.md +87 -0
- package/docs/tools/async-ids-log.md +80 -0
- package/docs/tools/device.md +132 -0
- package/docs/tools/introspection.md +67 -0
- package/docs/tools/lists.md +96 -0
- package/docs/tools/markdown.md +79 -0
- package/docs/tools/reactivity.md +288 -0
- package/docs/tools/state.md +103 -0
- package/docs/tools/styling.md +92 -0
- package/docs/tools/text-and-time.md +89 -0
- package/docs/tools/theme.md +102 -0
- package/docs/tools/validation.md +75 -0
- package/docs/tools/visual-effects.md +84 -0
- package/docs/widget/Accordion.md +144 -0
- package/docs/widget/AdMob.md +144 -0
- package/docs/widget/AdSense.md +133 -0
- package/docs/widget/AdaptiveScaffold.md +105 -0
- package/docs/widget/AlertDialog.md +103 -0
- package/docs/widget/AnimatedBox.md +130 -0
- package/docs/widget/AnimatedText.md +123 -0
- package/docs/widget/AppBar.md +118 -0
- package/docs/widget/Audio.md +135 -0
- package/docs/widget/Avatar.md +119 -0
- package/docs/widget/Badge.md +128 -0
- package/docs/widget/BottomNavigation.md +116 -0
- package/docs/widget/BottomSheet.md +125 -0
- package/docs/widget/Button.md +137 -0
- package/docs/widget/COMMON_PROPS.md +150 -0
- package/docs/widget/Card.md +125 -0
- package/docs/widget/Carousel.md +151 -0
- package/docs/widget/Chart.md +151 -0
- package/docs/widget/Checkbox.md +118 -0
- package/docs/widget/Chip.md +126 -0
- package/docs/widget/CircularBar.md +168 -0
- package/docs/widget/CircularChart.md +164 -0
- package/docs/widget/CodeViewer.md +130 -0
- package/docs/widget/CollapsibleSideBar.md +112 -0
- package/docs/widget/Column.md +129 -0
- package/docs/widget/Container.md +136 -0
- package/docs/widget/DataTable.md +150 -0
- package/docs/widget/Divider.md +109 -0
- package/docs/widget/DraggBox.md +129 -0
- package/docs/widget/Drawer.md +135 -0
- package/docs/widget/DrawerItem.md +98 -0
- package/docs/widget/Dropdown.md +139 -0
- package/docs/widget/DroppBox.md +152 -0
- package/docs/widget/FloatingActionButton.md +120 -0
- package/docs/widget/GridView.md +140 -0
- package/docs/widget/Icon.md +117 -0
- package/docs/widget/Image.md +125 -0
- package/docs/widget/Input.md +151 -0
- package/docs/widget/Inspector.md +92 -0
- package/docs/widget/InstallButton.md +128 -0
- package/docs/widget/ListTile.md +132 -0
- package/docs/widget/ListView.md +138 -0
- package/docs/widget/Markdown.md +175 -0
- package/docs/widget/MatrixRain.md +122 -0
- package/docs/widget/Modal.md +129 -0
- package/docs/widget/Pagination.md +135 -0
- package/docs/widget/ParallaxBox.md +128 -0
- package/docs/widget/ProgressBar.md +130 -0
- package/docs/widget/QRCode.md +117 -0
- package/docs/widget/README.md +188 -0
- package/docs/widget/Radio.md +123 -0
- package/docs/widget/Rating.md +131 -0
- package/docs/widget/Row.md +131 -0
- package/docs/widget/START_HERE.md +146 -0
- package/docs/widget/Scaffold.md +152 -0
- package/docs/widget/Skeleton.md +130 -0
- package/docs/widget/Slider.md +146 -0
- package/docs/widget/SnackBar.md +102 -0
- package/docs/widget/Stack.md +128 -0
- package/docs/widget/Stepper.md +145 -0
- package/docs/widget/Switch.md +118 -0
- package/docs/widget/Tabs.md +124 -0
- package/docs/widget/Text.md +133 -0
- package/docs/widget/Tooltip.md +145 -0
- package/docs/widget/TreeView.md +176 -0
- package/docs/widget/Video.md +127 -0
- package/docs/widget/_template.md +61 -0
- package/package.json +4 -2
- package/src/animations/AnimatedBox.js +32 -1
- package/src/animations/AnimatedText.js +7 -3
- package/src/animations/MatrixRain.js +37 -12
- package/src/animations/ParallaxBox.js +16 -3
- package/src/animations/animate.js +187 -58
- package/src/animations/index.js +1 -0
- package/src/core/runApp.js +13 -1
- package/src/create-index.sh +1 -1
- package/src/index.d.ts +227 -91
- package/src/index.js +1 -0
- package/src/navigations/AdaptiveScaffold.js +11 -2
- package/src/navigations/AppBar.js +8 -2
- package/src/navigations/BottomNavigation.js +24 -5
- package/src/navigations/DrawerItem.js +16 -3
- package/src/navigations/Scaffold.js +8 -1
- package/src/navigations/Tabs.js +40 -8
- package/src/tools/dimensions.js +11 -3
- package/src/tools/useState.js +139 -101
- package/src/utils/getWidgetProps.js +5 -3
- package/src/widget-factory/assignProps.js +30 -11
- package/src/widget-factory/processProps.js +17 -5
- package/src/widget-factory/reactiveValue.js +172 -0
- package/src/widget-factory/translateProps.js +777 -901
- package/src/widget-factory/warnings.js +15 -0
- package/src/widget-factory/widgetFactory.js +27 -0
- package/src/widgets/Accordion.js +6 -5
- package/src/widgets/AlertDialog.js +7 -5
- package/src/widgets/Audio.js +30 -8
- package/src/widgets/BottomSheet.js +24 -1
- package/src/widgets/Chart.js +4 -1
- package/src/widgets/Checkbox.js +16 -8
- package/src/widgets/CircularBar.js +12 -1
- package/src/widgets/CircularChart.js +4 -1
- package/src/widgets/CodeViewer.js +26 -8
- package/src/widgets/DataTable.js +11 -2
- package/src/widgets/Dropdown.js +5 -1
- package/src/widgets/FloatingActionButton.js +4 -7
- package/src/widgets/Image.js +7 -2
- package/src/widgets/Input.js +119 -6
- package/src/widgets/Inspector.js +16 -10
- package/src/widgets/ListView.js +80 -30
- package/src/widgets/Markdown.js +53 -8
- package/src/widgets/Modal.js +24 -1
- package/src/widgets/Pagination.js +6 -3
- package/src/widgets/ProgressBar.js +16 -13
- package/src/widgets/QRCode.js +9 -2
- package/src/widgets/Radio.js +11 -8
- package/src/widgets/Slider.js +26 -4
- package/src/widgets/SnackBar.js +20 -2
- package/src/widgets/Stack.js +36 -3
- package/src/widgets/Stepper.js +4 -3
- package/src/widgets/Switch.js +8 -5
- package/src/widgets/TreeView.js +3 -2
|
@@ -0,0 +1,145 @@
|
|
|
1
|
+
# Tooltip
|
|
2
|
+
|
|
3
|
+
Wraps a child widget and shows a labeled overlay bubble on hover or focus. The bubble is rendered as a portal on document.body so it is never clipped.
|
|
4
|
+
|
|
5
|
+
## When to use it
|
|
6
|
+
|
|
7
|
+
Use it to explain icons, buttons, or dense fields that cannot fit a visible label.
|
|
8
|
+
|
|
9
|
+
## Quick start
|
|
10
|
+
|
|
11
|
+
```javascript
|
|
12
|
+
import { Button, Tooltip, clipboard } from "flet-box";
|
|
13
|
+
|
|
14
|
+
const tip = Tooltip({
|
|
15
|
+
text: "Copy to clipboard",
|
|
16
|
+
child: Button({ text: "Copy" }),
|
|
17
|
+
});
|
|
18
|
+
```
|
|
19
|
+
|
|
20
|
+
> The prop table is generated from `src/index.d.ts`; the examples use only documented props.
|
|
21
|
+
|
|
22
|
+
## Props
|
|
23
|
+
|
|
24
|
+
| Prop | Type | Description |
|
|
25
|
+
| --- | --- | --- |
|
|
26
|
+
| `text` | `string` | Visible text content. |
|
|
27
|
+
| `child` | `Widget` | A single child widget. Alias: `children` for a list. |
|
|
28
|
+
| `position` | `'top' \| 'bottom' \| 'left' \| 'right'` | CSS `position` value, or `stack` for centered stacking. |
|
|
29
|
+
| `delay` | `number` | Delay before the animation starts, in milliseconds. |
|
|
30
|
+
| `bgColor` | `Color` | Background color. Alias: `backgroundColor`. |
|
|
31
|
+
| `textColor` | `Color` | Color of the button label. |
|
|
32
|
+
| `fontSize` | `number` | Size of the font. |
|
|
33
|
+
| `padding` | `Padding` | Space inside the widget, between its content and its border. |
|
|
34
|
+
| `borderRadius` | `number` | Rounds the corners of the widget. |
|
|
35
|
+
| `offset` | `number` | The `offset` value for the widget. |
|
|
36
|
+
| `showArrow` | `boolean` | Controls whether the arrow is shown. |
|
|
37
|
+
| `disabled` | `boolean` | Disables interaction and shows the non-interactive state. |
|
|
38
|
+
| `maxWidth` | `number` | Maximum width the widget may grow to. |
|
|
39
|
+
| `textAlign` | `'left' \| 'center' \| 'right'` | The `textAlign` value for the widget. |
|
|
40
|
+
| `zIndex` | `number` | Index used for the z. |
|
|
41
|
+
| `animationDuration` | `number` | Duration for the animation, in milliseconds. |
|
|
42
|
+
| `arrowSize` | `number` | Size of the arrow. |
|
|
43
|
+
| `borderColor` | `Color` | Color used for the border. |
|
|
44
|
+
| `borderWidth` | `number` | Width of the border. |
|
|
45
|
+
| `shadow` | `string` | Raw CSS `box-shadow` value, for a custom shadow. |
|
|
46
|
+
|
|
47
|
+
### Common props
|
|
48
|
+
|
|
49
|
+
Every widget also accepts these shared props — see [common props](COMMON_PROPS.md) for the full rules and aliases.
|
|
50
|
+
|
|
51
|
+
| Prop | Type | Description |
|
|
52
|
+
| --- | --- | --- |
|
|
53
|
+
| `width` | `Size` | Width of the widget. A number is pixels; a string uses any CSS unit. |
|
|
54
|
+
| `height` | `Size` | Height of the widget. A number is pixels; a string uses any CSS unit. |
|
|
55
|
+
| `size` | `Size` | Overall size preset or pixel value, depending on the widget. |
|
|
56
|
+
| `padding` | `Padding` | Space inside the widget, between its content and its border. |
|
|
57
|
+
| `margin` | `Margin` | Space outside the widget, between it and its neighbors. |
|
|
58
|
+
| `bgColor` | `Color` | Background color. Alias: `backgroundColor`. |
|
|
59
|
+
| `color` | `Color` | Foreground color, usually the text or icon color. |
|
|
60
|
+
| `borderRadius` | `number \| string` | Rounds the corners of the widget. |
|
|
61
|
+
| `elevation` | `number` | Shadow depth. Higher values lift the widget off the page. |
|
|
62
|
+
| `shadow` | `string` | Raw CSS `box-shadow` value, for a custom shadow. |
|
|
63
|
+
| `opacity` | `number` | Opacity from 0 (invisible) to 1 (fully opaque). |
|
|
64
|
+
| `visible` | `boolean` | Whether the widget is rendered and visible. |
|
|
65
|
+
| `disabled` | `boolean` | Disables interaction and shows the non-interactive state. |
|
|
66
|
+
| `onPress` | `(widget: Widget) => void` | Callback fired when the widget is pressed. Alias: `onClick`. |
|
|
67
|
+
| `onClick` | `(widget: Widget) => void` | Callback fired when the widget is clicked. Alias: `onPress`. |
|
|
68
|
+
| `id` | `string` | DOM `id` for the rendered element. |
|
|
69
|
+
| `className` | `string` | CSS class names applied to the rendered element. |
|
|
70
|
+
| `ref` | `(widget: Widget) => void` | Callback that receives the underlying DOM node. |
|
|
71
|
+
| `disableTransform` | `boolean` | Disables the default press/scale transform animation. |
|
|
72
|
+
|
|
73
|
+
## Examples
|
|
74
|
+
|
|
75
|
+
### Everyday
|
|
76
|
+
|
|
77
|
+
```javascript
|
|
78
|
+
import { Icon, Tooltip } from "flet-box";
|
|
79
|
+
|
|
80
|
+
const tip = Tooltip({
|
|
81
|
+
text: "Adds the item to your cart",
|
|
82
|
+
position: "bottom",
|
|
83
|
+
delay: 150,
|
|
84
|
+
child: Icon({ name: "shopping_cart" }),
|
|
85
|
+
});
|
|
86
|
+
```
|
|
87
|
+
|
|
88
|
+
### Full
|
|
89
|
+
|
|
90
|
+
```javascript
|
|
91
|
+
import { Button, Tooltip, rgba } from "flet-box";
|
|
92
|
+
|
|
93
|
+
const tip = Tooltip({
|
|
94
|
+
text: "Only visible to workspace admins",
|
|
95
|
+
child: Button({ text: "Share", variant: "outlined" }),
|
|
96
|
+
position: "right",
|
|
97
|
+
delay: 300,
|
|
98
|
+
offset: 12,
|
|
99
|
+
maxWidth: 240,
|
|
100
|
+
bgColor: "#111827",
|
|
101
|
+
textColor: "#f9fafb",
|
|
102
|
+
showArrow: true,
|
|
103
|
+
textAlign: "left",
|
|
104
|
+
borderRadius: 8,
|
|
105
|
+
shadow: "0 4px 12px rgba(0,0,0,0.25)",
|
|
106
|
+
animationDuration: 180,
|
|
107
|
+
});
|
|
108
|
+
```
|
|
109
|
+
|
|
110
|
+
## Tips
|
|
111
|
+
|
|
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.
|
|
118
|
+
|
|
119
|
+
## Accessibility
|
|
120
|
+
|
|
121
|
+
- The wrapped child keeps its focus handlers, so keyboard users tabbing onto it get
|
|
122
|
+
- the same tooltip as mouse hover.
|
|
123
|
+
|
|
124
|
+
## Behavior
|
|
125
|
+
|
|
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.
|
|
130
|
+
|
|
131
|
+
## Related widgets
|
|
132
|
+
|
|
133
|
+
- [Button](Button.md)
|
|
134
|
+
- [Icon](Icon.md)
|
|
135
|
+
- [Text](Text.md)
|
|
136
|
+
|
|
137
|
+
---
|
|
138
|
+
|
|
139
|
+
## Continue reading
|
|
140
|
+
|
|
141
|
+
- **Previous:** [SnackBar](SnackBar.md)
|
|
142
|
+
- **Next:** [ProgressBar](ProgressBar.md)
|
|
143
|
+
- **Index:** [Widget index](README.md) · [Start here](START_HERE.md)
|
|
144
|
+
|
|
145
|
+
You are reading **Chapter 4 · Feedback and overlays** (5 of 10).
|
|
@@ -0,0 +1,176 @@
|
|
|
1
|
+
# TreeView
|
|
2
|
+
|
|
3
|
+
TreeView renders a collapsible hierarchy from nodes, each with an id, label, optional icon, badge and children. It supports expand/collapse, selection and nested navigation.
|
|
4
|
+
|
|
5
|
+
## When to use it
|
|
6
|
+
|
|
7
|
+
Use it for file explorers, category menus or any nested set of items the user drills into.
|
|
8
|
+
|
|
9
|
+
## Quick start
|
|
10
|
+
|
|
11
|
+
```javascript
|
|
12
|
+
import { TreeView } from "flet-box";
|
|
13
|
+
|
|
14
|
+
const tree = TreeView({
|
|
15
|
+
nodes: [
|
|
16
|
+
{ id: "src", label: "src" },
|
|
17
|
+
],
|
|
18
|
+
});
|
|
19
|
+
```
|
|
20
|
+
|
|
21
|
+
> The prop table is generated from `src/index.d.ts`; the examples use only documented props.
|
|
22
|
+
|
|
23
|
+
## Props
|
|
24
|
+
|
|
25
|
+
| Prop | Type | Description |
|
|
26
|
+
| --- | --- | --- |
|
|
27
|
+
| `nodes` | `Array<{` | Tree nodes, each with `id`, `label`, and optional `children`. |
|
|
28
|
+
| `id` | `string` | DOM `id` for the rendered element. |
|
|
29
|
+
| `label` | `string` | Label or caption shown near the control. |
|
|
30
|
+
| `icon` | `string` | Name of the icon to render. |
|
|
31
|
+
| `iconColor` | `Color` | Color of the field icons. |
|
|
32
|
+
| `children` | `any[]` | An array of child widgets. Alias: `child` for a single child. |
|
|
33
|
+
| `badge` | `string \| number` | The `badge` value for the widget. |
|
|
34
|
+
| `onSelect` | `(node: any) => void` | Fired when the widget or an option is selected. |
|
|
35
|
+
| `onToggle` | `(nodeId: string, expanded: boolean) => void` | Fired with the new toggled state. |
|
|
36
|
+
| `expandedNodes` | `string[]` | Ids of nodes that start expanded. |
|
|
37
|
+
| `indent` | `number` | Indentation depth used when printing nested structures. |
|
|
38
|
+
| `showIcons` | `boolean` | Controls whether the icons is shown. |
|
|
39
|
+
| `folderIcon` | `string` | Icon for the folder. |
|
|
40
|
+
| `folderOpenIcon` | `string` | Icon for the folder open. |
|
|
41
|
+
| `fileIcon` | `string` | Icon for the file. |
|
|
42
|
+
| `expandIcon` | `string` | Icon for the expand. |
|
|
43
|
+
| `collapseIcon` | `string` | Icon for the collapse. |
|
|
44
|
+
| `defaultExpanded` | `boolean` | Expands top-level nodes by default. |
|
|
45
|
+
| `selectable` | `boolean` | Lets the user select a tree node. |
|
|
46
|
+
| `selectedNodeId` | `string \| null` | Id of the currently selected node. |
|
|
47
|
+
| `bgColor` | `Color` | Background color. Alias: `backgroundColor`. |
|
|
48
|
+
| `hoverBgColor` | `Color` | Background color for the hover. |
|
|
49
|
+
| `selectedBgColor` | `Color` | Background color for the selected. |
|
|
50
|
+
| `textColor` | `Color` | Color of the button label. |
|
|
51
|
+
| `selectedTextColor` | `Color` | Color used for the selected text. |
|
|
52
|
+
| `iconColor` | `Color` | Color of the field icons. |
|
|
53
|
+
| `folderIconColor` | `Color` | Color used for the folder icon. |
|
|
54
|
+
| `borderColor` | `Color` | Color used for the border. |
|
|
55
|
+
| `nodePadding` | `Padding` | Padding for the node. |
|
|
56
|
+
| `nodeGap` | `number` | Space for the node. |
|
|
57
|
+
| `childrenGap` | `number` | Space for the children. |
|
|
58
|
+
| `borderRadius` | `number` | Rounds the corners of the widget. |
|
|
59
|
+
| `fontSize` | `number` | Size of the font. |
|
|
60
|
+
| `iconSize` | `number` | Size of the field icons. |
|
|
61
|
+
| `transitionDuration` | `string` | Duration for the transition, in milliseconds. |
|
|
62
|
+
|
|
63
|
+
### Common props
|
|
64
|
+
|
|
65
|
+
Every widget also accepts these shared props — see [common props](COMMON_PROPS.md) for the full rules and aliases.
|
|
66
|
+
|
|
67
|
+
| Prop | Type | Description |
|
|
68
|
+
| --- | --- | --- |
|
|
69
|
+
| `width` | `Size` | Width of the widget. A number is pixels; a string uses any CSS unit. |
|
|
70
|
+
| `height` | `Size` | Height of the widget. A number is pixels; a string uses any CSS unit. |
|
|
71
|
+
| `size` | `Size` | Overall size preset or pixel value, depending on the widget. |
|
|
72
|
+
| `padding` | `Padding` | Space inside the widget, between its content and its border. |
|
|
73
|
+
| `margin` | `Margin` | Space outside the widget, between it and its neighbors. |
|
|
74
|
+
| `bgColor` | `Color` | Background color. Alias: `backgroundColor`. |
|
|
75
|
+
| `color` | `Color` | Foreground color, usually the text or icon color. |
|
|
76
|
+
| `borderRadius` | `number \| string` | Rounds the corners of the widget. |
|
|
77
|
+
| `elevation` | `number` | Shadow depth. Higher values lift the widget off the page. |
|
|
78
|
+
| `shadow` | `string` | Raw CSS `box-shadow` value, for a custom shadow. |
|
|
79
|
+
| `opacity` | `number` | Opacity from 0 (invisible) to 1 (fully opaque). |
|
|
80
|
+
| `visible` | `boolean` | Whether the widget is rendered and visible. |
|
|
81
|
+
| `disabled` | `boolean` | Disables interaction and shows the non-interactive state. |
|
|
82
|
+
| `onPress` | `(widget: Widget) => void` | Callback fired when the widget is pressed. Alias: `onClick`. |
|
|
83
|
+
| `onClick` | `(widget: Widget) => void` | Callback fired when the widget is clicked. Alias: `onPress`. |
|
|
84
|
+
| `id` | `string` | DOM `id` for the rendered element. |
|
|
85
|
+
| `className` | `string` | CSS class names applied to the rendered element. |
|
|
86
|
+
| `ref` | `(widget: Widget) => void` | Callback that receives the underlying DOM node. |
|
|
87
|
+
| `disableTransform` | `boolean` | Disables the default press/scale transform animation. |
|
|
88
|
+
|
|
89
|
+
## Examples
|
|
90
|
+
|
|
91
|
+
### Everyday
|
|
92
|
+
|
|
93
|
+
```javascript
|
|
94
|
+
import { TreeView } from "flet-box";
|
|
95
|
+
|
|
96
|
+
const tree = TreeView({
|
|
97
|
+
nodes: [
|
|
98
|
+
{
|
|
99
|
+
id: "src",
|
|
100
|
+
label: "src",
|
|
101
|
+
children: [
|
|
102
|
+
{ id: "app", label: "app.js" },
|
|
103
|
+
{ id: "router", label: "Router.js" },
|
|
104
|
+
],
|
|
105
|
+
},
|
|
106
|
+
],
|
|
107
|
+
showIcons: true,
|
|
108
|
+
onSelect: (node) => console.log(node.id),
|
|
109
|
+
});
|
|
110
|
+
```
|
|
111
|
+
|
|
112
|
+
### Full
|
|
113
|
+
|
|
114
|
+
```javascript
|
|
115
|
+
import { TreeView } from "flet-box";
|
|
116
|
+
|
|
117
|
+
const tree = TreeView({
|
|
118
|
+
nodes: [
|
|
119
|
+
{
|
|
120
|
+
id: "src",
|
|
121
|
+
label: "src",
|
|
122
|
+
icon: "folder",
|
|
123
|
+
children: [
|
|
124
|
+
{ id: "app", label: "app.js", icon: "description" },
|
|
125
|
+
{ id: "router", label: "Router.js", badge: 2 },
|
|
126
|
+
],
|
|
127
|
+
},
|
|
128
|
+
],
|
|
129
|
+
expandedNodes: ["src"],
|
|
130
|
+
defaultExpanded: true,
|
|
131
|
+
selectable: true,
|
|
132
|
+
showIcons: true,
|
|
133
|
+
selectedNodeId: "app",
|
|
134
|
+
indent: 20,
|
|
135
|
+
nodeGap: 4,
|
|
136
|
+
childrenGap: 4,
|
|
137
|
+
fontSize: 14,
|
|
138
|
+
transitionDuration: "200ms",
|
|
139
|
+
hoverBgColor: "#f1f5f9",
|
|
140
|
+
selectedBgColor: "#dbeafe",
|
|
141
|
+
onToggle: (nodeId, expanded) => console.log(nodeId, expanded),
|
|
142
|
+
onSelect: (node) => console.log(node.id),
|
|
143
|
+
});
|
|
144
|
+
```
|
|
145
|
+
|
|
146
|
+
## Tips
|
|
147
|
+
|
|
148
|
+
- Give every node a stable unique id; expandedNodes and selectedNodeId reference those ids.
|
|
149
|
+
- Set selectable to false for navigation trees where tapping should only toggle groups.
|
|
150
|
+
- Use defaultExpanded to open first-level groups on first render.
|
|
151
|
+
|
|
152
|
+
## Accessibility
|
|
153
|
+
|
|
154
|
+
- Expose meaningful label text and do not rely only on icons to describe a node.
|
|
155
|
+
- Keep onSelect behavior predictable so keyboard users understand what activation does.
|
|
156
|
+
|
|
157
|
+
## Behavior
|
|
158
|
+
|
|
159
|
+
- Nodes toggle locally and report expansion through onToggle with the nodeId and expanded flag.
|
|
160
|
+
- Selection is reported through onSelect as the node object and can be controlled with selectedNodeId.
|
|
161
|
+
|
|
162
|
+
## Related widgets
|
|
163
|
+
|
|
164
|
+
- [ListView](ListView.md)
|
|
165
|
+
- [ListTile](ListTile.md)
|
|
166
|
+
- [Accordion](Accordion.md)
|
|
167
|
+
|
|
168
|
+
---
|
|
169
|
+
|
|
170
|
+
## Continue reading
|
|
171
|
+
|
|
172
|
+
- **Previous:** [Accordion](Accordion.md)
|
|
173
|
+
- **Next:** [Carousel](Carousel.md)
|
|
174
|
+
- **Index:** [Widget index](README.md) · [Start here](START_HERE.md)
|
|
175
|
+
|
|
176
|
+
You are reading **Chapter 5 · Navigation and flows** (3 of 5).
|
|
@@ -0,0 +1,127 @@
|
|
|
1
|
+
# Video
|
|
2
|
+
|
|
3
|
+
Renders a native <video> element with proper media attributes and a convenient playback API. Helpers for play, pause, stop, restart, and volume.
|
|
4
|
+
|
|
5
|
+
## When to use it
|
|
6
|
+
|
|
7
|
+
Use it to embed a clip, trailer, ambient background video, or lecture recording.
|
|
8
|
+
|
|
9
|
+
## Quick start
|
|
10
|
+
|
|
11
|
+
```javascript
|
|
12
|
+
import { Video } from "flet-box";
|
|
13
|
+
|
|
14
|
+
const clip = Video({
|
|
15
|
+
src: "/media/intro.mp4",
|
|
16
|
+
});
|
|
17
|
+
```
|
|
18
|
+
|
|
19
|
+
> The prop table is generated from `src/index.d.ts`; the examples use only documented props.
|
|
20
|
+
|
|
21
|
+
## Props
|
|
22
|
+
|
|
23
|
+
| Prop | Type | Description |
|
|
24
|
+
| --- | --- | --- |
|
|
25
|
+
| `src` | `string` | Resource URL for the image, audio, or video. |
|
|
26
|
+
| `width` | `number \| string` | Width of the widget. A number is pixels; a string uses any CSS unit. |
|
|
27
|
+
| `height` | `number \| string` | Height of the widget. A number is pixels; a string uses any CSS unit. |
|
|
28
|
+
| `autoplay` | `boolean` | Starts playback automatically. |
|
|
29
|
+
| `controls` | `boolean` | Shows the native media playback controls. |
|
|
30
|
+
| `loop` | `boolean` | Restarts playback when it reaches the end. |
|
|
31
|
+
| `muted` | `boolean` | Starts playback with the audio muted. |
|
|
32
|
+
| `poster` | `string` | Image shown before a video starts playing. |
|
|
33
|
+
| `ref` | `(video: HTMLVideoElement) => void` | Callback that receives the underlying DOM node. |
|
|
34
|
+
|
|
35
|
+
### Common props
|
|
36
|
+
|
|
37
|
+
Every widget also accepts these shared props — see [common props](COMMON_PROPS.md) for the full rules and aliases.
|
|
38
|
+
|
|
39
|
+
| Prop | Type | Description |
|
|
40
|
+
| --- | --- | --- |
|
|
41
|
+
| `width` | `Size` | Width of the widget. A number is pixels; a string uses any CSS unit. |
|
|
42
|
+
| `height` | `Size` | Height of the widget. A number is pixels; a string uses any CSS unit. |
|
|
43
|
+
| `size` | `Size` | Overall size preset or pixel value, depending on the widget. |
|
|
44
|
+
| `padding` | `Padding` | Space inside the widget, between its content and its border. |
|
|
45
|
+
| `margin` | `Margin` | Space outside the widget, between it and its neighbors. |
|
|
46
|
+
| `bgColor` | `Color` | Background color. Alias: `backgroundColor`. |
|
|
47
|
+
| `color` | `Color` | Foreground color, usually the text or icon color. |
|
|
48
|
+
| `borderRadius` | `number \| string` | Rounds the corners of the widget. |
|
|
49
|
+
| `elevation` | `number` | Shadow depth. Higher values lift the widget off the page. |
|
|
50
|
+
| `shadow` | `string` | Raw CSS `box-shadow` value, for a custom shadow. |
|
|
51
|
+
| `opacity` | `number` | Opacity from 0 (invisible) to 1 (fully opaque). |
|
|
52
|
+
| `visible` | `boolean` | Whether the widget is rendered and visible. |
|
|
53
|
+
| `disabled` | `boolean` | Disables interaction and shows the non-interactive state. |
|
|
54
|
+
| `onPress` | `(widget: Widget) => void` | Callback fired when the widget is pressed. Alias: `onClick`. |
|
|
55
|
+
| `onClick` | `(widget: Widget) => void` | Callback fired when the widget is clicked. Alias: `onPress`. |
|
|
56
|
+
| `id` | `string` | DOM `id` for the rendered element. |
|
|
57
|
+
| `className` | `string` | CSS class names applied to the rendered element. |
|
|
58
|
+
| `ref` | `(widget: Widget) => void` | Callback that receives the underlying DOM node. |
|
|
59
|
+
| `disableTransform` | `boolean` | Disables the default press/scale transform animation. |
|
|
60
|
+
|
|
61
|
+
## Examples
|
|
62
|
+
|
|
63
|
+
### Everyday
|
|
64
|
+
|
|
65
|
+
```javascript
|
|
66
|
+
import { Video } from "flet-box";
|
|
67
|
+
|
|
68
|
+
const clip = Video({
|
|
69
|
+
src: "/media/intro.mp4",
|
|
70
|
+
controls: true,
|
|
71
|
+
width: "100%",
|
|
72
|
+
height: 360,
|
|
73
|
+
poster: "/media/intro-poster.jpg",
|
|
74
|
+
});
|
|
75
|
+
```
|
|
76
|
+
|
|
77
|
+
### Full
|
|
78
|
+
|
|
79
|
+
```javascript
|
|
80
|
+
import { Video } from "flet-box";
|
|
81
|
+
|
|
82
|
+
const clip = Video({
|
|
83
|
+
src: "/media/demo.mp4",
|
|
84
|
+
width: "100%",
|
|
85
|
+
height: 480,
|
|
86
|
+
controls: true,
|
|
87
|
+
autoplay: false,
|
|
88
|
+
loop: true,
|
|
89
|
+
muted: true,
|
|
90
|
+
poster: "/media/demo-poster.jpg",
|
|
91
|
+
ref: (video) => video.playVideo(),
|
|
92
|
+
});
|
|
93
|
+
```
|
|
94
|
+
|
|
95
|
+
## Tips
|
|
96
|
+
|
|
97
|
+
- controls, loop, muted, and autoplay are set as element properties, not CSS, so they
|
|
98
|
+
- work even though they look like styling props.
|
|
99
|
+
- Browsers block autoplay with sound; pair autoplay: true with muted: true for a
|
|
100
|
+
- reliable ambient loop.
|
|
101
|
+
- The ref callback receives the element extended with playVideo, pauseVideo, stop,
|
|
102
|
+
- restart, volumeUp, and muteVideo helpers.
|
|
103
|
+
|
|
104
|
+
## Accessibility
|
|
105
|
+
|
|
106
|
+
- Keep controls: true so keyboard and screen-reader users can operate playback.
|
|
107
|
+
|
|
108
|
+
## Behavior
|
|
109
|
+
|
|
110
|
+
- playVideo swallows the browser's autoplay rejection instead of throwing, so it is
|
|
111
|
+
- safe to call from a click handler.
|
|
112
|
+
|
|
113
|
+
## Related widgets
|
|
114
|
+
|
|
115
|
+
- [Audio](Audio.md)
|
|
116
|
+
- [Image](Image.md)
|
|
117
|
+
- [Card](Card.md)
|
|
118
|
+
|
|
119
|
+
---
|
|
120
|
+
|
|
121
|
+
## Continue reading
|
|
122
|
+
|
|
123
|
+
- **Previous:** [Audio](Audio.md)
|
|
124
|
+
- **Next:** [DraggBox](DraggBox.md)
|
|
125
|
+
- **Index:** [Widget index](README.md) · [Start here](START_HERE.md)
|
|
126
|
+
|
|
127
|
+
You are reading **Chapter 7 · Media and drag & drop** (2 of 4).
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
# WidgetName
|
|
2
|
+
|
|
3
|
+
## Overview
|
|
4
|
+
|
|
5
|
+
Explain what the widget is for in one or two sentences.
|
|
6
|
+
|
|
7
|
+
## When to use it
|
|
8
|
+
|
|
9
|
+
Describe the situation in which you reach for this widget.
|
|
10
|
+
|
|
11
|
+
## Quick start
|
|
12
|
+
|
|
13
|
+
```javascript
|
|
14
|
+
import { WidgetName } from "flet-box";
|
|
15
|
+
|
|
16
|
+
const example = WidgetName({
|
|
17
|
+
// the smallest useful call
|
|
18
|
+
});
|
|
19
|
+
```
|
|
20
|
+
|
|
21
|
+
## Props
|
|
22
|
+
|
|
23
|
+
| Prop | Type | Description |
|
|
24
|
+
| --- | --- | --- |
|
|
25
|
+
| `propName` | `Type` | What the prop does. |
|
|
26
|
+
|
|
27
|
+
## Examples
|
|
28
|
+
|
|
29
|
+
### Everyday
|
|
30
|
+
|
|
31
|
+
Show the most common combination of props.
|
|
32
|
+
|
|
33
|
+
### Full
|
|
34
|
+
|
|
35
|
+
Show advanced layout, styling and events.
|
|
36
|
+
|
|
37
|
+
## Tips
|
|
38
|
+
|
|
39
|
+
- Practical, widget-specific advice.
|
|
40
|
+
|
|
41
|
+
## Accessibility
|
|
42
|
+
|
|
43
|
+
- Keyboard and screen-reader considerations.
|
|
44
|
+
|
|
45
|
+
## Behavior
|
|
46
|
+
|
|
47
|
+
- Layout, interaction and re-render notes.
|
|
48
|
+
|
|
49
|
+
## Related widgets
|
|
50
|
+
|
|
51
|
+
- [Container](Container.md)
|
|
52
|
+
|
|
53
|
+
---
|
|
54
|
+
|
|
55
|
+
## Continue reading
|
|
56
|
+
|
|
57
|
+
- **Previous:** ...
|
|
58
|
+
- **Next:** ...
|
|
59
|
+
- **Index:** [Widget index](README.md) · [Start here](START_HERE.md)
|
|
60
|
+
|
|
61
|
+
You are reading **Chapter N · Title** (i of m).
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "flet-box",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.5",
|
|
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,8 @@
|
|
|
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"
|
|
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 && python3 tools/snippets-creator-flet-box/build_snippets.py --check && node scripts/check-snippets.mjs",
|
|
23
|
+
"test:browser": "node scripts/run-browser-tests.mjs"
|
|
23
24
|
},
|
|
24
25
|
"keywords": [
|
|
25
26
|
"fletbox",
|
|
@@ -51,6 +52,7 @@
|
|
|
51
52
|
"files": [
|
|
52
53
|
"bin/",
|
|
53
54
|
"src/",
|
|
55
|
+
"docs/",
|
|
54
56
|
"README.md",
|
|
55
57
|
"LICENSE"
|
|
56
58
|
],
|
|
@@ -334,6 +334,24 @@ const interpolateGradient = (gradient1, gradient2, t) => {
|
|
|
334
334
|
* @param {string} keyframes - The keyframe body (everything inside `@keyframes name { … }`).
|
|
335
335
|
* @returns {void}
|
|
336
336
|
*/
|
|
337
|
+
/**
|
|
338
|
+
* Stable hash of a keyframe body, used as the generated animation name so that
|
|
339
|
+
* identical keyframes are injected only once.
|
|
340
|
+
*
|
|
341
|
+
* @param {string} keyframes
|
|
342
|
+
* @returns {string}
|
|
343
|
+
*/
|
|
344
|
+
const hashKeyframes = (keyframes) => {
|
|
345
|
+
let h1 = 0x811c9dc5;
|
|
346
|
+
let h2 = 0x01000193;
|
|
347
|
+
for (let i = 0; i < keyframes.length; i++) {
|
|
348
|
+
const c = keyframes.charCodeAt(i);
|
|
349
|
+
h1 = Math.imul(h1 ^ c, 0x01000193);
|
|
350
|
+
h2 = Math.imul(h2 + c, 0x85ebca6b) ^ (h2 >>> 13);
|
|
351
|
+
}
|
|
352
|
+
return (h1 >>> 0).toString(36) + (h2 >>> 0).toString(36);
|
|
353
|
+
};
|
|
354
|
+
|
|
337
355
|
const injectKeyframes = (name, keyframes) => {
|
|
338
356
|
if (injectedKeyframes.has(name)) return;
|
|
339
357
|
const style = document.createElement("style");
|
|
@@ -365,6 +383,15 @@ const generateKeyframes = (animations) => {
|
|
|
365
383
|
const effect = effectMap[anim.effect] || anim.effect;
|
|
366
384
|
const { from, to, reverse = true } = anim;
|
|
367
385
|
|
|
386
|
+
// A descriptor without `from`/`to` is malformed. Skip it with a warning
|
|
387
|
+
// rather than throwing a TypeError out of the caller's entire render.
|
|
388
|
+
if (from === undefined || to === undefined) {
|
|
389
|
+
console.warn(
|
|
390
|
+
`⚠️ [AnimatedBox] Skipping animation "${anim.effect}": "from" and "to" are required.`,
|
|
391
|
+
);
|
|
392
|
+
return;
|
|
393
|
+
}
|
|
394
|
+
|
|
368
395
|
let value;
|
|
369
396
|
let color;
|
|
370
397
|
|
|
@@ -589,8 +616,12 @@ export const AnimatedBox = ({
|
|
|
589
616
|
child.style.background = firstAnim.from;
|
|
590
617
|
}
|
|
591
618
|
|
|
592
|
-
const name = `anim-${Date.now()}-${animationCounter++}`;
|
|
593
619
|
const keyframes = generateKeyframes(animations);
|
|
620
|
+
// The name is derived from the keyframe body so identical animations reuse a
|
|
621
|
+
// single <style>. A per-call unique name (`Date.now()`) made the dedupe check
|
|
622
|
+
// in `injectKeyframes` dead code: every call appended a permanent <style> to
|
|
623
|
+
// document.head, and AnimatedText calls this once per letter.
|
|
624
|
+
const name = `anim-${hashKeyframes(keyframes)}`;
|
|
594
625
|
injectKeyframes(name, keyframes);
|
|
595
626
|
|
|
596
627
|
const duration = animations[0]?.duration || 500;
|
|
@@ -39,9 +39,13 @@ export const AnimatedText = ({
|
|
|
39
39
|
if (!child) return null;
|
|
40
40
|
if (!animations || animations.length === 0) return child;
|
|
41
41
|
|
|
42
|
-
// Extract text content and props from the original Text widget
|
|
43
|
-
|
|
44
|
-
|
|
42
|
+
// Extract text content and props from the original Text widget. The factory
|
|
43
|
+
// stores props in `_originalProps`; `_props` is never assigned by anything, so
|
|
44
|
+
// reading it here silently dropped every style (font, size, colour) and the
|
|
45
|
+
// documented per-letter inheritance never happened.
|
|
46
|
+
const sourceProps = child._originalProps || child._props || {};
|
|
47
|
+
const originalText = sourceProps.text || child.textContent || "";
|
|
48
|
+
const originalProps = { ...sourceProps };
|
|
45
49
|
// Ensure no background animation styles bleed into individual letter widgets
|
|
46
50
|
delete originalProps.animations;
|
|
47
51
|
|
|
@@ -52,6 +52,11 @@ export const MatrixRain = (props = {}) => {
|
|
|
52
52
|
let drops = [];
|
|
53
53
|
let columns = 0;
|
|
54
54
|
let resizeObserver = null;
|
|
55
|
+
let observedParent = null;
|
|
56
|
+
// The canvas is returned to the caller and appended afterwards, so it is NOT
|
|
57
|
+
// connected when the animation starts. `wasConnected` tracks that first mount
|
|
58
|
+
// so the loop can stop when the canvas is later removed from the document.
|
|
59
|
+
let wasConnected = false;
|
|
55
60
|
|
|
56
61
|
/**
|
|
57
62
|
* Determines the canvas dimensions based on positioning mode.
|
|
@@ -84,14 +89,17 @@ export const MatrixRain = (props = {}) => {
|
|
|
84
89
|
*/
|
|
85
90
|
const resizeCanvas = () => {
|
|
86
91
|
if (!canvas) return;
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
92
|
+
// The canvas is returned to the caller and appended afterwards, so on the
|
|
93
|
+
// first call there is no parent yet. Create the observer once and (re)attach
|
|
94
|
+
// it whenever the canvas ends up living in a different parent.
|
|
95
|
+
if (position === "absolute" && typeof ResizeObserver !== "undefined") {
|
|
96
|
+
if (!resizeObserver) resizeObserver = new ResizeObserver(resizeCanvas);
|
|
97
|
+
const parent = canvas.parentElement;
|
|
98
|
+
if (parent && observedParent !== parent) {
|
|
99
|
+
if (observedParent) resizeObserver.unobserve(observedParent);
|
|
100
|
+
resizeObserver.observe(parent);
|
|
101
|
+
observedParent = parent;
|
|
102
|
+
}
|
|
95
103
|
}
|
|
96
104
|
const { width, height } = getCanvasSize();
|
|
97
105
|
canvas.width = width;
|
|
@@ -154,6 +162,25 @@ export const MatrixRain = (props = {}) => {
|
|
|
154
162
|
const draw = () => {
|
|
155
163
|
if (!ctx || !canvas) return;
|
|
156
164
|
|
|
165
|
+
// The canvas is handed back to the caller and appended afterwards, so it is
|
|
166
|
+
// disconnected while the animation starts. Once it HAS been mounted, a
|
|
167
|
+
// disconnect means it was removed from the document — stop there.
|
|
168
|
+
//
|
|
169
|
+
// Nothing else covers that path: `runApp`'s teardownTree and Scaffold's
|
|
170
|
+
// observer call `_cleanup()`, but the lifecycle observer in
|
|
171
|
+
// `src/widget-factory/lifecycle.js` only fires `onUnmount`, and a raw canvas
|
|
172
|
+
// has no such hook. Without this guard the loop would keep re-arming at
|
|
173
|
+
// 60fps painting into a detached canvas, forever.
|
|
174
|
+
if (canvas.isConnected) {
|
|
175
|
+
if (!wasConnected) {
|
|
176
|
+
wasConnected = true;
|
|
177
|
+
resizeCanvas(); // size to the real parent and attach the observer
|
|
178
|
+
}
|
|
179
|
+
} else if (wasConnected) {
|
|
180
|
+
cleanup();
|
|
181
|
+
return;
|
|
182
|
+
}
|
|
183
|
+
|
|
157
184
|
// Semi-transparent black overlay produces the trailing-fade effect
|
|
158
185
|
ctx.fillStyle = `rgba(0, 0, 0, ${fadeAmount})`;
|
|
159
186
|
ctx.fillRect(0, 0, canvas.width, canvas.height);
|
|
@@ -188,10 +215,8 @@ export const MatrixRain = (props = {}) => {
|
|
|
188
215
|
};
|
|
189
216
|
|
|
190
217
|
window.addEventListener("resize", handleResize);
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
if (canvas.parentElement) resizeObserver.observe(canvas.parentElement);
|
|
194
|
-
}
|
|
218
|
+
// NOTE: the parent ResizeObserver is attached from `resizeCanvas()` (see
|
|
219
|
+
// above), because the canvas has no parent until the caller appends it.
|
|
195
220
|
|
|
196
221
|
/**
|
|
197
222
|
* Stops the animation loop, removes event listeners, disconnects the
|