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
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
// core/assignProps.js
|
|
2
2
|
import { setStyles } from "./tools.js";
|
|
3
|
+
import { resolveReactive } from "./reactiveValue.js";
|
|
3
4
|
|
|
4
5
|
/**
|
|
5
6
|
* Extracts the real value from a prop that may be a reactive accessor or a
|
|
@@ -14,15 +15,7 @@ import { setStyles } from "./tools.js";
|
|
|
14
15
|
* @param {*} val - The raw prop value (may be reactive or plain).
|
|
15
16
|
* @returns {*} The resolved runtime value.
|
|
16
17
|
*/
|
|
17
|
-
const getValue =
|
|
18
|
-
if (typeof val === "function" && val._isReactive) {
|
|
19
|
-
return val();
|
|
20
|
-
}
|
|
21
|
-
if (val && typeof val === "object" && val._isReactive === true) {
|
|
22
|
-
return val._value !== undefined ? val._value : val.valueOf();
|
|
23
|
-
}
|
|
24
|
-
return val;
|
|
25
|
-
};
|
|
18
|
+
const getValue = resolveReactive;
|
|
26
19
|
|
|
27
20
|
/**
|
|
28
21
|
* HTML attributes whose mere presence means "true". Writing them through
|
|
@@ -66,6 +59,28 @@ const applySpecial = (widget, key, value) => {
|
|
|
66
59
|
case "variant":
|
|
67
60
|
widget.dataset.variant = val;
|
|
68
61
|
break;
|
|
62
|
+
case "visible": {
|
|
63
|
+
// Hiding must not destroy the `display` the widget's own styles chose
|
|
64
|
+
// (`flex` for a Row, `inline-flex` for an Input…), so the previous inline
|
|
65
|
+
// value is stashed and handed back on show. The stash is only reused while
|
|
66
|
+
// we are still the reason the element is hidden: if an update set a new
|
|
67
|
+
// `display` in the meantime, that value is the truth and is left alone.
|
|
68
|
+
if (val) {
|
|
69
|
+
if (
|
|
70
|
+
widget._hiddenByVisibleProp !== undefined &&
|
|
71
|
+
widget.style.display === "none"
|
|
72
|
+
) {
|
|
73
|
+
widget.style.display = widget._hiddenByVisibleProp;
|
|
74
|
+
}
|
|
75
|
+
delete widget._hiddenByVisibleProp;
|
|
76
|
+
} else if (widget.style.display !== "none") {
|
|
77
|
+
if (widget._hiddenByVisibleProp === undefined) {
|
|
78
|
+
widget._hiddenByVisibleProp = widget.style.display;
|
|
79
|
+
}
|
|
80
|
+
widget.style.display = "none";
|
|
81
|
+
}
|
|
82
|
+
break;
|
|
83
|
+
}
|
|
69
84
|
}
|
|
70
85
|
};
|
|
71
86
|
|
|
@@ -79,7 +94,7 @@ const applySpecial = (widget, key, value) => {
|
|
|
79
94
|
* `click` is assigned via `onclick` for reliable override behaviour.
|
|
80
95
|
* 4. **attributes** – applied with `setAttribute`, with special handling for
|
|
81
96
|
* `className` and boolean attributes (`disabled`, `readOnly`, `hidden`, …).
|
|
82
|
-
* 5. **special** – delegated to `applySpecial` (
|
|
97
|
+
* 5. **special** – delegated to `applySpecial` (`value`, `variant`, `visible`).
|
|
83
98
|
*
|
|
84
99
|
* Any keys not in the known set are handled as a flat-prop fallback: `on*`
|
|
85
100
|
* functions become event listeners, common HTML attributes are set directly, and
|
|
@@ -110,7 +125,11 @@ export const assignProps = (widget, props) => {
|
|
|
110
125
|
// ============================================================
|
|
111
126
|
// 2. TEXT
|
|
112
127
|
// ============================================================
|
|
113
|
-
|
|
128
|
+
// `null` is `processProps`' sentinel for "this prop set carries no text".
|
|
129
|
+
// Only an explicitly present value (including "") may touch textContent:
|
|
130
|
+
// assigning null stringifies to "" and therefore REMOVES every child, which
|
|
131
|
+
// silently wiped widgets on any `update()` that did not re-pass `child`.
|
|
132
|
+
if (props.textContent !== undefined && props.textContent !== null) {
|
|
114
133
|
const textValue = getValue(props.textContent);
|
|
115
134
|
if (widget.tagName === "INPUT" || widget.tagName === "TEXTAREA") {
|
|
116
135
|
if (widget.value !== textValue) widget.value = textValue;
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
// core/processProps.js
|
|
2
|
-
import { getPropDefinition, ATTRIBUTE_DOM_SET } from "./translateProps.js";
|
|
2
|
+
import { getPropDefinition, ATTRIBUTE_DOM_SET, PASSTHROUGH_PREFIXES } from "./translateProps.js";
|
|
3
3
|
import { toREM } from "./remTool.js"; // Centralized REM conversion utility
|
|
4
|
+
import { resolveReactive } from "./reactiveValue.js";
|
|
4
5
|
|
|
5
6
|
/**
|
|
6
7
|
* Processes raw props and classifies them into:
|
|
@@ -26,8 +27,12 @@ export const processProps = (props, tag = "div", widgetName = null) => {
|
|
|
26
27
|
// Derive widget name from tag (e.g., 'div' → 'Div', 'span' → 'Span')
|
|
27
28
|
const name = widgetName || tag.charAt(0).toUpperCase() + tag.slice(1);
|
|
28
29
|
|
|
29
|
-
for (const [key,
|
|
30
|
-
if (
|
|
30
|
+
for (const [key, rawValue] of Object.entries(props)) {
|
|
31
|
+
if (rawValue === undefined || rawValue === null) continue;
|
|
32
|
+
// Resolve the reactive-prop protocol once, here. A live value must be READ
|
|
33
|
+
// now so `width: count` yields a number (and gets its px/rem unit), and a
|
|
34
|
+
// function must never reach a CSS assignment.
|
|
35
|
+
const value = resolveReactive(rawValue);
|
|
31
36
|
|
|
32
37
|
// `style` is deliberately NOT part of the API: FletBox uses flat, aliased
|
|
33
38
|
// CSS props. Fail loudly instead of silently ignoring the object.
|
|
@@ -48,6 +53,7 @@ export const processProps = (props, tag = "div", widgetName = null) => {
|
|
|
48
53
|
// Shorthands may fan out to several CSS props (e.g. `px` →
|
|
49
54
|
// paddingLeft + paddingRight). Everything else writes to its domProp.
|
|
50
55
|
const cssValue = applyUnit(def, value);
|
|
56
|
+
if (cssValue === undefined) break;
|
|
51
57
|
const targets = def.targets || [def.domProp];
|
|
52
58
|
for (const target of targets) style[target] = cssValue;
|
|
53
59
|
break;
|
|
@@ -79,7 +85,7 @@ export const processProps = (props, tag = "div", widgetName = null) => {
|
|
|
79
85
|
}
|
|
80
86
|
} else {
|
|
81
87
|
// Unknown prop → intelligent fallback
|
|
82
|
-
if (
|
|
88
|
+
if (PASSTHROUGH_PREFIXES.some((prefix) => key.startsWith(prefix))) {
|
|
83
89
|
attributes[key] = value;
|
|
84
90
|
} else if (key.startsWith("on") && typeof value === "function") {
|
|
85
91
|
const eventName = key.slice(2).toLowerCase();
|
|
@@ -98,6 +104,9 @@ export const processProps = (props, tag = "div", widgetName = null) => {
|
|
|
98
104
|
/**
|
|
99
105
|
* Applies the correct CSS unit to a numeric value based on the prop definition.
|
|
100
106
|
*
|
|
107
|
+
* - A prop with `boolValues` maps `true`/`false` to the CSS the property
|
|
108
|
+
* actually accepts (e.g. `wrap: true` → `flex-wrap: wrap`); an `undefined`
|
|
109
|
+
* mapping skips the assignment.
|
|
101
110
|
* - `true` / `false` are coerced to `1` / `0` (unitless).
|
|
102
111
|
* - Non-numeric values pass through unchanged.
|
|
103
112
|
* - `unit: "none"` returns the raw number without a suffix.
|
|
@@ -106,9 +115,12 @@ export const processProps = (props, tag = "div", widgetName = null) => {
|
|
|
106
115
|
*
|
|
107
116
|
* @param {Object} def - Prop definition from the prop database (see `translateProps.js`).
|
|
108
117
|
* @param {*} value - The value to convert.
|
|
109
|
-
* @returns {string|number} Value with the correct CSS unit applied.
|
|
118
|
+
* @returns {string|number|undefined} Value with the correct CSS unit applied.
|
|
110
119
|
*/
|
|
111
120
|
function applyUnit(def, value) {
|
|
121
|
+
if (def.boolValues && typeof value === "boolean") {
|
|
122
|
+
return def.boolValues[String(value)];
|
|
123
|
+
}
|
|
112
124
|
if (value === true) return 1;
|
|
113
125
|
if (value === false) return 0;
|
|
114
126
|
if (typeof value !== "number") return value;
|
|
@@ -0,0 +1,172 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @file reactiveValue.js
|
|
3
|
+
* @description
|
|
4
|
+
* The reactive-prop protocol shared by `useState`, the widget factory and the
|
|
5
|
+
* prop pipeline.
|
|
6
|
+
*
|
|
7
|
+
* A prop value may be a *reactive value*: an object or function flagged with
|
|
8
|
+
* `_isReactive` that reports the current value of a state key. The factory
|
|
9
|
+
* resolves it whenever the prop is applied, and — when the value carries a
|
|
10
|
+
* `_stateKey` — it also **subscribes** the widget to that key so a later change
|
|
11
|
+
* updates only this widget instead of re-rendering the whole app.
|
|
12
|
+
*
|
|
13
|
+
* Two shapes are supported:
|
|
14
|
+
*
|
|
15
|
+
* - **Live** (what `useState` returns): a callable that reads the store on every
|
|
16
|
+
* call. `valueOf`/`toString` also read live, so `${count}`, `count + 1` and
|
|
17
|
+
* CSS assignment all get the current value.
|
|
18
|
+
* - **Snapshot** (legacy): an object with a frozen `_value`. Still resolved, but
|
|
19
|
+
* it cannot auto-subscribe because it has no live source.
|
|
20
|
+
*
|
|
21
|
+
* @module widget-factory/reactiveValue
|
|
22
|
+
*/
|
|
23
|
+
|
|
24
|
+
/**
|
|
25
|
+
* True while `resolveReactive` is reading a value on behalf of the factory.
|
|
26
|
+
*
|
|
27
|
+
* The distinction matters: a read the FACTORY performs (to fill a prop) is a
|
|
28
|
+
* direct binding, but a read the COMPONENT performs (`${count}`, `count > 3`,
|
|
29
|
+
* `count.valueOf()`) means the value also drives structure or computation, so the
|
|
30
|
+
* app has to re-run as well. Reconciling the two is what keeps
|
|
31
|
+
* `Text({ text: count })` surgical without breaking a sibling conditional.
|
|
32
|
+
*/
|
|
33
|
+
let resolving = false;
|
|
34
|
+
|
|
35
|
+
/**
|
|
36
|
+
* Depth of the component-render pass, so reads in an event handler or a timer
|
|
37
|
+
* (which run outside the pass) do not mark a key as structurally read.
|
|
38
|
+
*/
|
|
39
|
+
let renderPassDepth = 0;
|
|
40
|
+
|
|
41
|
+
/**
|
|
42
|
+
* Keys the component read structurally during the pass that just finished.
|
|
43
|
+
*
|
|
44
|
+
* Rebuilt by every render pass: a component re-reads everything it consumes, so
|
|
45
|
+
* what the last pass saw is the complete picture. Keeping the keys of *earlier*
|
|
46
|
+
* passes instead would pin the app to full re-renders forever after one
|
|
47
|
+
* conditional read, which is exactly what the surgical binding exists to avoid.
|
|
48
|
+
*/
|
|
49
|
+
let structuralKeys = new Set();
|
|
50
|
+
|
|
51
|
+
/** The keys collected by the pass currently running, or `null` between passes. */
|
|
52
|
+
let passKeys = null;
|
|
53
|
+
|
|
54
|
+
/** Marks the start of a component-render pass. */
|
|
55
|
+
export const beginRenderPass = () => {
|
|
56
|
+
if (renderPassDepth === 0) passKeys = new Set();
|
|
57
|
+
renderPassDepth++;
|
|
58
|
+
};
|
|
59
|
+
|
|
60
|
+
/** Marks the end of a component-render pass and publishes what it observed. */
|
|
61
|
+
export const endRenderPass = () => {
|
|
62
|
+
if (renderPassDepth === 0) return;
|
|
63
|
+
renderPassDepth--;
|
|
64
|
+
if (renderPassDepth === 0) {
|
|
65
|
+
if (passKeys) structuralKeys = passKeys;
|
|
66
|
+
passKeys = null;
|
|
67
|
+
}
|
|
68
|
+
};
|
|
69
|
+
|
|
70
|
+
/**
|
|
71
|
+
* True when the last render pass consumed `key` structurally, so a change to it
|
|
72
|
+
* needs an app render on top of the surgical prop patch.
|
|
73
|
+
*
|
|
74
|
+
* @param {string} key
|
|
75
|
+
* @returns {boolean}
|
|
76
|
+
*/
|
|
77
|
+
export const isStructuralRead = (key) => structuralKeys.has(key);
|
|
78
|
+
|
|
79
|
+
/** Forgets every observed key. Used by hot-reload teardown. */
|
|
80
|
+
export const resetStructuralReads = () => {
|
|
81
|
+
structuralKeys = new Set();
|
|
82
|
+
passKeys = renderPassDepth > 0 ? new Set() : null;
|
|
83
|
+
};
|
|
84
|
+
|
|
85
|
+
/**
|
|
86
|
+
* True when `val` is a reactive value (live or snapshot).
|
|
87
|
+
*
|
|
88
|
+
* @param {*} val
|
|
89
|
+
* @returns {boolean}
|
|
90
|
+
*/
|
|
91
|
+
export const isReactive = (val) => Boolean(val) && val._isReactive === true;
|
|
92
|
+
|
|
93
|
+
/**
|
|
94
|
+
* The state key a reactive value is bound to, or `null` when it is not bound.
|
|
95
|
+
*
|
|
96
|
+
* @param {*} val
|
|
97
|
+
* @returns {string|null}
|
|
98
|
+
*/
|
|
99
|
+
export const reactiveKeyOf = (val) => (isReactive(val) ? val._stateKey ?? null : null);
|
|
100
|
+
|
|
101
|
+
/**
|
|
102
|
+
* Resolves a reactive value to its current value. Plain values pass through.
|
|
103
|
+
*
|
|
104
|
+
* A live value is invoked, which is what makes it stay current: every time the
|
|
105
|
+
* prop is re-applied the store is read again. The read is flagged as a factory
|
|
106
|
+
* read so it is not mistaken for a structural one.
|
|
107
|
+
*
|
|
108
|
+
* @param {*} val
|
|
109
|
+
* @returns {*}
|
|
110
|
+
*/
|
|
111
|
+
export const resolveReactive = (val) => {
|
|
112
|
+
if (typeof val === "function" && val._isReactive) {
|
|
113
|
+
// Save and restore instead of clearing: a reactive whose `valueOf` reads
|
|
114
|
+
// another one would otherwise leave the inner read flagged as the factory's
|
|
115
|
+
// and the outer one reported as a structural read.
|
|
116
|
+
const wasResolving = resolving;
|
|
117
|
+
resolving = true;
|
|
118
|
+
try {
|
|
119
|
+
return val();
|
|
120
|
+
} finally {
|
|
121
|
+
resolving = wasResolving;
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
if (val && typeof val === "object" && val._isReactive === true) {
|
|
125
|
+
return val._value !== undefined ? val._value : val.valueOf();
|
|
126
|
+
}
|
|
127
|
+
return val;
|
|
128
|
+
};
|
|
129
|
+
|
|
130
|
+
/**
|
|
131
|
+
* Builds the live reactive value returned by `useState`.
|
|
132
|
+
*
|
|
133
|
+
* It is a **function** (so `resolveReactive` calls it and always gets the
|
|
134
|
+
* current value) decorated with `valueOf`/`toString` (so template literals and
|
|
135
|
+
* arithmetic work) and a `_value` getter (so the legacy `state._value` read
|
|
136
|
+
* keeps working — now live instead of frozen).
|
|
137
|
+
*
|
|
138
|
+
* Every read that the component itself performs during a render pass is recorded
|
|
139
|
+
* in the pass's structural-key set, because such a read means the value is
|
|
140
|
+
* consumed structurally and the app must re-render too.
|
|
141
|
+
*
|
|
142
|
+
* @param {() => *} read - Reads the current value from the store.
|
|
143
|
+
* @param {string} key - The state key this value is bound to.
|
|
144
|
+
* @returns {Function} The live reactive value.
|
|
145
|
+
*/
|
|
146
|
+
export const createReactiveValue = (read, key) => {
|
|
147
|
+
const live = () => {
|
|
148
|
+
const value = read();
|
|
149
|
+
if (!resolving && passKeys) passKeys.add(key);
|
|
150
|
+
return value;
|
|
151
|
+
};
|
|
152
|
+
live._isReactive = true;
|
|
153
|
+
live._stateKey = key;
|
|
154
|
+
live.valueOf = () => live();
|
|
155
|
+
live.toString = () => String(live());
|
|
156
|
+
Object.defineProperty(live, "_value", {
|
|
157
|
+
get: () => live(),
|
|
158
|
+
configurable: true,
|
|
159
|
+
});
|
|
160
|
+
return live;
|
|
161
|
+
};
|
|
162
|
+
|
|
163
|
+
export default {
|
|
164
|
+
isReactive,
|
|
165
|
+
reactiveKeyOf,
|
|
166
|
+
resolveReactive,
|
|
167
|
+
createReactiveValue,
|
|
168
|
+
isStructuralRead,
|
|
169
|
+
resetStructuralReads,
|
|
170
|
+
beginRenderPass,
|
|
171
|
+
endRenderPass,
|
|
172
|
+
};
|