flet-box 1.1.0 → 1.1.2
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 +16 -12
- package/bin/commands/checkUi.js +276 -45
- package/bin/commands/create.js +8 -1
- package/bin/commands/createBundle.js +18 -6
- package/bin/commands/createScreen.js +1 -1
- package/bin/commands/runBundle.js +1 -1
- package/bin/utils/bundleConfig.js +47 -3
- package/bin/utils/colors.js +0 -8
- package/bin/utils/helpers.js +0 -5
- package/bin/utils/images/jpeg.js +2 -3
- package/bin/utils/templates.js +101 -85
- package/docs/README.md +24 -1
- package/docs/cli/README.md +51 -10
- package/docs/guides/README.md +5 -2
- package/docs/guides/accessibility.md +282 -0
- package/docs/guides/clean-ui.md +53 -8
- package/docs/guides/first-app.md +6 -7
- package/docs/guides/minification-and-protection.md +1 -1
- package/docs/guides/mobile-and-platforms.md +51 -0
- package/docs/guides/online-updates.md +18 -6
- package/docs/guides/utilities.md +116 -4
- package/docs/guides/widget-structure.md +30 -0
- package/docs/tools/README.md +1 -1
- package/docs/tools/animation.md +134 -11
- package/docs/tools/device.md +75 -3
- package/docs/tools/text-and-time.md +116 -6
- package/docs/widget/Accordion.md +2 -0
- package/docs/widget/AnimatedBox.md +46 -20
- package/docs/widget/AnimatedText.md +13 -7
- package/docs/widget/Badge.md +1 -0
- package/docs/widget/COMMON_PROPS.md +26 -3
- package/docs/widget/Chart.md +1 -0
- package/docs/widget/Checkbox.md +7 -1
- package/docs/widget/CircularChart.md +2 -0
- package/docs/widget/Drawer.md +1 -0
- package/docs/widget/GridView.md +4 -1
- package/docs/widget/Input.md +2 -0
- package/docs/widget/InstallButton.md +1 -0
- package/docs/widget/Markdown.md +4 -0
- package/docs/widget/Rating.md +2 -0
- package/docs/widget/Slider.md +2 -0
- package/docs/widget/Stack.md +6 -5
- package/docs/widget/Stepper.md +2 -0
- package/docs/widget/Tooltip.md +3 -1
- package/package.json +3 -2
- package/skills/fletbox-design/SKILL.md +390 -14
- package/skills/fletbox-motion/SKILL.md +145 -47
- package/skills/fletbox-rules/SKILL.md +140 -1
- package/src/animations/AnimatedBox.js +321 -226
- package/src/animations/MatrixRain.js +7 -1
- package/src/animations/ParallaxBox.js +13 -10
- package/src/animations/animate.js +269 -106
- package/src/animations/color.js +91 -0
- package/src/animations/easings.js +275 -0
- package/src/animations/index.js +21 -0
- package/src/animations/motion.js +204 -0
- package/src/animations/transitions.js +327 -0
- package/src/core/runApp.js +0 -6
- package/src/helpers/boxEdges.js +69 -0
- package/src/helpers/html.js +39 -0
- package/src/index.d.ts +377 -25
- package/src/index.js +77 -0
- package/src/navigations/AdaptiveScaffold.js +6 -2
- package/src/navigations/AppBar.js +16 -7
- package/src/navigations/BottomNavigation.js +24 -1
- package/src/navigations/CollapsibleSideBar.js +0 -1
- package/src/navigations/Drawer.js +32 -1
- package/src/navigations/DrawerItem.js +1 -1
- package/src/navigations/Router.js +0 -1
- package/src/navigations/Scaffold.js +9 -3
- package/src/navigations/Tabs.js +104 -31
- package/src/services/RamStore.js +1 -2
- package/src/tools/breakpoints.js +113 -0
- package/src/tools/createList.js +0 -2
- package/src/tools/fonts.js +99 -0
- package/src/tools/index.js +74 -1
- package/src/tools/margin.js +5 -63
- package/src/tools/padding.js +5 -63
- package/src/tools/print.js +0 -8
- package/src/tools/scale.js +9 -2
- package/src/tools/time.js +56 -15
- package/src/tools/useState.js +1 -54
- package/src/utils/fieldFont.js +77 -0
- package/src/utils/focusRing.js +73 -0
- package/src/utils/focusScope.js +113 -0
- package/src/utils/markdownParser.js +7 -9
- package/src/utils/readableInk.js +7 -1
- package/src/utils/stackLayout.js +55 -0
- package/src/utils/styleInjector.js +25 -0
- package/src/utils/syntaxHighlight.js +1 -17
- package/src/utils/themes.js +15 -0
- package/src/utils/visualEffects.js +49 -47
- package/src/widget-factory/createWidget.js +16 -3
- package/src/widget-factory/effects.js +76 -3
- package/src/widget-factory/reactiveValue.js +0 -7
- package/src/widget-factory/tools.js +26 -143
- package/src/widget-factory/translateProps.js +5 -0
- package/src/widget-factory/widgetFactory.js +1 -1
- package/src/widgets/Accordion.js +70 -12
- package/src/widgets/AdMob.js +1 -1
- package/src/widgets/AdSense.js +1 -1
- package/src/widgets/AlertDialog.js +11 -9
- package/src/widgets/Avatar.js +10 -1
- package/src/widgets/Badge.js +7 -1
- package/src/widgets/BottomSheet.js +39 -5
- package/src/widgets/Chart.js +41 -9
- package/src/widgets/Checkbox.js +59 -9
- package/src/widgets/Chip.js +13 -1
- package/src/widgets/CircularBar.js +17 -5
- package/src/widgets/CircularChart.js +24 -2
- package/src/widgets/CodeViewer.js +5 -3
- package/src/widgets/Dropdown.js +223 -20
- package/src/widgets/GridView.js +17 -1
- package/src/widgets/Icon.js +21 -0
- package/src/widgets/Input.js +75 -44
- package/src/widgets/InstallButton.js +8 -2
- package/src/widgets/ListTile.js +6 -5
- package/src/widgets/ListView.js +21 -7
- package/src/widgets/Markdown.js +25 -44
- package/src/widgets/Modal.js +43 -6
- package/src/widgets/Pagination.js +35 -3
- package/src/widgets/ProgressBar.js +18 -0
- package/src/widgets/Radio.js +7 -0
- package/src/widgets/Rating.js +104 -16
- package/src/widgets/Skeleton.js +9 -5
- package/src/widgets/Slider.js +87 -7
- package/src/widgets/SnackBar.js +30 -1
- package/src/widgets/Stack.js +25 -13
- package/src/widgets/Stepper.js +112 -64
- package/src/widgets/Switch.js +10 -1
- package/src/widgets/Tooltip.js +93 -10
- package/src/widgets/TreeView.js +5 -5
- package/src/create-index.sh +0 -237
- package/src/widget-factory/pixTool.js +0 -40
- package/src/widget-factory/stringTool.js +0 -26
|
@@ -0,0 +1,327 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* transitions.js - The named entrances and feedback gestures.
|
|
3
|
+
*
|
|
4
|
+
* Between an app that animates and one that looks animated there are three
|
|
5
|
+
* movements: something arriving, something leaving, and something saying "that
|
|
6
|
+
* was wrong". Writing them per screen is how a codebase ends up with eleven
|
|
7
|
+
* slightly different entrances, and each one is a hand-rolled loop that no longer
|
|
8
|
+
* obeys the reduced-motion preference because the engine never saw it.
|
|
9
|
+
*
|
|
10
|
+
* These are the three that carry a product, built on the same `runAnimation()`
|
|
11
|
+
* loop everything else uses, so they inherit its guarantees for free: one
|
|
12
|
+
* registered loop per widget and property, the end value always lands, a cancel
|
|
13
|
+
* function that also resolves an `await`, and duration collapsing to zero when the
|
|
14
|
+
* user asked for reduced motion.
|
|
15
|
+
*
|
|
16
|
+
* Every preset is described once, as the list of loops the gesture is made of, and
|
|
17
|
+
* the two forms — the one that hands back a cancel function and the one you `await`
|
|
18
|
+
* — are that same list run two ways. A preset that grows an option cannot end up
|
|
19
|
+
* meaning one thing to `slideIn` and another to `slideInAsync`.
|
|
20
|
+
*
|
|
21
|
+
* @module animations/transitions
|
|
22
|
+
*/
|
|
23
|
+
|
|
24
|
+
import { runAnimation } from "./animate.js";
|
|
25
|
+
|
|
26
|
+
/**
|
|
27
|
+
* One loop of a gesture, as the arguments `runAnimation` takes.
|
|
28
|
+
*
|
|
29
|
+
* @typedef {object} GestureStep
|
|
30
|
+
* @property {string} property - The CSS property or transform function.
|
|
31
|
+
* @property {number|string} from - Starting value.
|
|
32
|
+
* @property {number|string} to - Ending value.
|
|
33
|
+
* @property {number} duration - Milliseconds.
|
|
34
|
+
* @property {string|((t: number) => number)} easing - Curve name or curve.
|
|
35
|
+
* @property {((progress: number) => number|string)} [valueAt] - Custom value curve.
|
|
36
|
+
*/
|
|
37
|
+
|
|
38
|
+
/**
|
|
39
|
+
* Stops every loop a preset started on a widget.
|
|
40
|
+
*
|
|
41
|
+
* @param {(...: any) => boolean} cancels - The cancel functions of the loops.
|
|
42
|
+
* @returns {() => boolean} One cancel for the whole gesture.
|
|
43
|
+
*/
|
|
44
|
+
const combine = (cancels) => () =>
|
|
45
|
+
cancels.map((cancel) => cancel()).some(Boolean);
|
|
46
|
+
|
|
47
|
+
/**
|
|
48
|
+
* Runs a gesture and hands back one cancel for the whole of it.
|
|
49
|
+
*
|
|
50
|
+
* @param {HTMLElement|object} widget - The target widget or DOM element.
|
|
51
|
+
* @param {GestureStep[]} steps
|
|
52
|
+
* @returns {() => boolean}
|
|
53
|
+
*/
|
|
54
|
+
const play = (widget, steps) =>
|
|
55
|
+
combine(
|
|
56
|
+
steps.map(({ property, from, to, duration, easing, valueAt }) =>
|
|
57
|
+
runAnimation(widget, property, from, to, duration, easing, valueAt ?? null),
|
|
58
|
+
),
|
|
59
|
+
);
|
|
60
|
+
|
|
61
|
+
/**
|
|
62
|
+
* Runs a gesture and resolves when every loop of it has landed.
|
|
63
|
+
*
|
|
64
|
+
* @param {HTMLElement|object} widget - The target widget or DOM element.
|
|
65
|
+
* @param {GestureStep[]} steps
|
|
66
|
+
* @returns {Promise<HTMLElement|object>} Resolves with `widget` — or as soon as any
|
|
67
|
+
* loop is cancelled or replaced, so `await` never hangs.
|
|
68
|
+
*/
|
|
69
|
+
const playAsync = (widget, steps) =>
|
|
70
|
+
Promise.all(
|
|
71
|
+
steps.map(
|
|
72
|
+
({ property, from, to, duration, easing, valueAt }) =>
|
|
73
|
+
new Promise((resolve) =>
|
|
74
|
+
runAnimation(
|
|
75
|
+
widget,
|
|
76
|
+
property,
|
|
77
|
+
from,
|
|
78
|
+
to,
|
|
79
|
+
duration,
|
|
80
|
+
easing,
|
|
81
|
+
valueAt ?? null,
|
|
82
|
+
resolve,
|
|
83
|
+
),
|
|
84
|
+
),
|
|
85
|
+
),
|
|
86
|
+
).then(() => widget);
|
|
87
|
+
|
|
88
|
+
/**
|
|
89
|
+
* Resolves the axis a `direction` names.
|
|
90
|
+
*
|
|
91
|
+
* The direction is the way the element *travels* as it arrives, which is how
|
|
92
|
+
* people say it out loud ("slide up"), and the axis it moves along is the second
|
|
93
|
+
* step: `up` and `down` are vertical travel, so the offset lives in `translateY`.
|
|
94
|
+
*
|
|
95
|
+
* @param {string} direction
|
|
96
|
+
* @returns {{ property: string, sign: number }}
|
|
97
|
+
*/
|
|
98
|
+
const axisFor = (direction) => {
|
|
99
|
+
switch (direction) {
|
|
100
|
+
case "down":
|
|
101
|
+
return { property: "translateY", sign: -1 };
|
|
102
|
+
case "left":
|
|
103
|
+
return { property: "translateX", sign: 1 };
|
|
104
|
+
case "right":
|
|
105
|
+
return { property: "translateX", sign: -1 };
|
|
106
|
+
case "up":
|
|
107
|
+
default:
|
|
108
|
+
return { property: "translateY", sign: 1 };
|
|
109
|
+
}
|
|
110
|
+
};
|
|
111
|
+
|
|
112
|
+
/**
|
|
113
|
+
* The travel of a `slide`, as one framework-unit offset on the axis the direction
|
|
114
|
+
* names, plus the fade that carries it.
|
|
115
|
+
*
|
|
116
|
+
* @param {object} options - See {@link slideIn}.
|
|
117
|
+
* @param {"up"|"down"|"left"|"right"} [options.direction="up"]
|
|
118
|
+
* @param {number} [options.distance=16]
|
|
119
|
+
* @param {number} [options.duration=240]
|
|
120
|
+
* @param {string|((t: number) => number)} [options.easing="easeOut"]
|
|
121
|
+
* @param {boolean} [options.fade=true]
|
|
122
|
+
* @param {boolean} [options.leaving=false] - The exit mirrors the entrance.
|
|
123
|
+
* @returns {GestureStep[]}
|
|
124
|
+
*/
|
|
125
|
+
const slideSteps = ({
|
|
126
|
+
direction = "up",
|
|
127
|
+
distance = 16,
|
|
128
|
+
duration = 240,
|
|
129
|
+
easing = "easeOut",
|
|
130
|
+
fade = true,
|
|
131
|
+
leaving = false,
|
|
132
|
+
}) => {
|
|
133
|
+
const { property, sign } = axisFor(direction);
|
|
134
|
+
const offset = Math.abs(Number(distance) || 0) * sign;
|
|
135
|
+
const steps = leaving
|
|
136
|
+
? [{ property, from: 0, to: -offset, duration, easing }]
|
|
137
|
+
: [{ property, from: offset, to: 0, duration, easing }];
|
|
138
|
+
if (fade) {
|
|
139
|
+
steps.push({
|
|
140
|
+
property: "opacity",
|
|
141
|
+
from: leaving ? 1 : 0,
|
|
142
|
+
to: leaving ? 0 : 1,
|
|
143
|
+
duration,
|
|
144
|
+
easing,
|
|
145
|
+
});
|
|
146
|
+
}
|
|
147
|
+
return steps;
|
|
148
|
+
};
|
|
149
|
+
|
|
150
|
+
/**
|
|
151
|
+
* The decaying side-to-side (or up-and-down) movement of a `shake`.
|
|
152
|
+
*
|
|
153
|
+
* @param {object} options - See {@link shake}.
|
|
154
|
+
* @param {"x"|"y"} [options.axis="x"]
|
|
155
|
+
* @param {number} [options.distance=6]
|
|
156
|
+
* @param {number} [options.cycles=3]
|
|
157
|
+
* @param {number} [options.duration=320]
|
|
158
|
+
* @returns {GestureStep[]}
|
|
159
|
+
*/
|
|
160
|
+
const shakeSteps = ({
|
|
161
|
+
axis = "x",
|
|
162
|
+
distance = 6,
|
|
163
|
+
cycles = 3,
|
|
164
|
+
duration = 320,
|
|
165
|
+
}) => {
|
|
166
|
+
const property = axis === "y" ? "translateY" : "translateX";
|
|
167
|
+
const amplitude = Math.abs(Number(distance) || 0);
|
|
168
|
+
const swings = Math.max(1, Number(cycles) || 3);
|
|
169
|
+
return [
|
|
170
|
+
{
|
|
171
|
+
property,
|
|
172
|
+
from: 0,
|
|
173
|
+
to: 0,
|
|
174
|
+
duration,
|
|
175
|
+
easing: "linear",
|
|
176
|
+
// (1 - t) makes each swing smaller than the last, so the gesture ends at rest
|
|
177
|
+
// instead of stopping mid-swing and leaving the row off its own column.
|
|
178
|
+
valueAt: (progress) =>
|
|
179
|
+
amplitude * Math.sin(progress * Math.PI * 2 * swings) * (1 - progress),
|
|
180
|
+
},
|
|
181
|
+
];
|
|
182
|
+
};
|
|
183
|
+
|
|
184
|
+
/**
|
|
185
|
+
* Brings a widget onto the screen: a short travel plus a fade, as one gesture.
|
|
186
|
+
*
|
|
187
|
+
* This is the entrance the design rules describe (opacity + a small `translate`,
|
|
188
|
+
* one direction, under 500ms) with the arithmetic already done, so a screen does
|
|
189
|
+
* not need three `animate()` calls and a `Promise.all` to say "this appeared".
|
|
190
|
+
*
|
|
191
|
+
* @param {HTMLElement|object} widget - The target widget or DOM element.
|
|
192
|
+
* @param {object} [options]
|
|
193
|
+
* @param {"up"|"down"|"left"|"right"} [options.direction="up"] - The way the
|
|
194
|
+
* element travels as it arrives. `up` starts below its resting place.
|
|
195
|
+
* @param {number} [options.distance=16] - How far it travels, in framework units:
|
|
196
|
+
* a bare `16` is a `rem` offset through the engine, so it grows with the
|
|
197
|
+
* reader's font exactly like the widget it belongs to.
|
|
198
|
+
* @param {number} [options.duration=240] - Milliseconds; stay under 500.
|
|
199
|
+
* @param {string|((t: number) => number)} [options.easing="easeOut"] - Curve name
|
|
200
|
+
* or curve. An entrance decelerates — `easeIn` reads as a screen that is late.
|
|
201
|
+
* @param {boolean} [options.fade=true] - Also animate `opacity` from 0.
|
|
202
|
+
* @returns {() => boolean} Cancel function for both loops.
|
|
203
|
+
*/
|
|
204
|
+
export const slideIn = (widget, options = {}) =>
|
|
205
|
+
play(widget, slideSteps(options));
|
|
206
|
+
|
|
207
|
+
/**
|
|
208
|
+
* The awaitable form of {@link slideIn}.
|
|
209
|
+
*
|
|
210
|
+
* @param {HTMLElement|object} widget - The target widget or DOM element.
|
|
211
|
+
* @param {object} [options] - See {@link slideIn}.
|
|
212
|
+
* @returns {Promise<HTMLElement|object>} Resolves with `widget` when the element
|
|
213
|
+
* has arrived, or as soon as either loop is cancelled or replaced.
|
|
214
|
+
*/
|
|
215
|
+
export const slideInAsync = (widget, options = {}) =>
|
|
216
|
+
playAsync(widget, slideSteps(options));
|
|
217
|
+
|
|
218
|
+
/**
|
|
219
|
+
* The scale a `popIn` travels through, plus the optional fade.
|
|
220
|
+
*
|
|
221
|
+
* @param {object} options - See {@link popIn}.
|
|
222
|
+
* @returns {GestureStep[]}
|
|
223
|
+
*/
|
|
224
|
+
const popSteps = ({
|
|
225
|
+
from = 0.94,
|
|
226
|
+
to = 1,
|
|
227
|
+
duration = 180,
|
|
228
|
+
easing = "easeOutBack",
|
|
229
|
+
fade = false,
|
|
230
|
+
}) => {
|
|
231
|
+
const steps = [{ property: "scale", from, to, duration, easing }];
|
|
232
|
+
if (fade) steps.push({ property: "opacity", from: 0, to: 1, duration, easing });
|
|
233
|
+
return steps;
|
|
234
|
+
};
|
|
235
|
+
|
|
236
|
+
/**
|
|
237
|
+
* Brings a widget in from slightly smaller than its final size.
|
|
238
|
+
*
|
|
239
|
+
* `scale` from 0 is a dot that pops, and from 1.2 it is a banner that slams.
|
|
240
|
+
* 0.94 → 1 with a `Back` curve is the version that reads as an object being set
|
|
241
|
+
* down, which is the one worth having a name for.
|
|
242
|
+
*
|
|
243
|
+
* @param {HTMLElement|object} widget - The target widget or DOM element.
|
|
244
|
+
* @param {object} [options]
|
|
245
|
+
* @param {number} [options.from=0.94] - Starting scale; keep it above 0.9.
|
|
246
|
+
* @param {number} [options.to=1] - Resting scale.
|
|
247
|
+
* @param {number} [options.duration=180] - Milliseconds.
|
|
248
|
+
* @param {string|((t: number) => number)} [options.easing="easeOutBack"] - Curve;
|
|
249
|
+
* the small overshoot is the whole effect, and a spring works here too.
|
|
250
|
+
* @param {boolean} [options.fade=false] - Also animate `opacity` from 0.
|
|
251
|
+
* @returns {() => boolean} Cancel function.
|
|
252
|
+
*/
|
|
253
|
+
export const popIn = (widget, options = {}) =>
|
|
254
|
+
play(widget, popSteps(options));
|
|
255
|
+
|
|
256
|
+
/**
|
|
257
|
+
* The awaitable form of {@link popIn}.
|
|
258
|
+
*
|
|
259
|
+
* @param {HTMLElement|object} widget - The target widget or DOM element.
|
|
260
|
+
* @param {object} [options] - See {@link popIn}.
|
|
261
|
+
* @returns {Promise<HTMLElement|object>} Resolves with `widget` when it settles.
|
|
262
|
+
*/
|
|
263
|
+
export const popInAsync = (widget, options = {}) =>
|
|
264
|
+
playAsync(widget, popSteps(options));
|
|
265
|
+
|
|
266
|
+
/**
|
|
267
|
+
* Says "that was wrong" without a word: a short, decaying side-to-side move.
|
|
268
|
+
*
|
|
269
|
+
* One loop with a decaying sine rather than a chain of animations, because a
|
|
270
|
+
* multi-phase gesture made of separate calls cannot be cancelled as a gesture —
|
|
271
|
+
* and a shake that outlives the error it belongs to is worse than no shake.
|
|
272
|
+
* `valueAt` receives eased progress, so the curve stays triangular in time.
|
|
273
|
+
*
|
|
274
|
+
* @param {HTMLElement|object} widget - The target widget or DOM element.
|
|
275
|
+
* @param {object} [options]
|
|
276
|
+
* @param {"x"|"y"} [options.axis="x"] - Which way it shakes; `y` for a vertical list.
|
|
277
|
+
* @param {number} [options.distance=6] - Amplitude of the first swing, in framework
|
|
278
|
+
* units (a bare `6` is `0.375rem`).
|
|
279
|
+
* @param {number} [options.cycles=3] - Number of swings; more reads as a glitch.
|
|
280
|
+
* @param {number} [options.duration=320] - Milliseconds.
|
|
281
|
+
* @returns {() => boolean} Cancel function; cancelling leaves the element at the
|
|
282
|
+
* offset it held at that moment, so call it from `onUnmount` rather than mid-error.
|
|
283
|
+
*/
|
|
284
|
+
export const shake = (widget, options = {}) =>
|
|
285
|
+
play(widget, shakeSteps(options));
|
|
286
|
+
|
|
287
|
+
/**
|
|
288
|
+
* The awaitable form of {@link shake}.
|
|
289
|
+
*
|
|
290
|
+
* @param {HTMLElement|object} widget - The target widget or DOM element.
|
|
291
|
+
* @param {object} [options] - See {@link shake}.
|
|
292
|
+
* @returns {Promise<HTMLElement|object>} Resolves with `widget` when the shake ends.
|
|
293
|
+
*/
|
|
294
|
+
export const shakeAsync = (widget, options = {}) =>
|
|
295
|
+
playAsync(widget, shakeSteps(options));
|
|
296
|
+
|
|
297
|
+
/**
|
|
298
|
+
* Moves a widget out of the screen and leaves it invisible.
|
|
299
|
+
*
|
|
300
|
+
* The exit is the mirror of {@link slideIn} and one notch shorter: motion leaving
|
|
301
|
+
* is a courtesy, motion arriving is information. It does not remove anything from
|
|
302
|
+
* the DOM — the caller hides or unmounts the widget when this resolves, which is
|
|
303
|
+
* the only reason to `await` an exit.
|
|
304
|
+
*
|
|
305
|
+
* @param {HTMLElement|object} widget - The target widget or DOM element.
|
|
306
|
+
* @param {object} [options]
|
|
307
|
+
* @param {"up"|"down"|"left"|"right"} [options.direction="down"] - The way it leaves.
|
|
308
|
+
* @param {number} [options.distance=12] - How far it travels, in framework units.
|
|
309
|
+
* @param {number} [options.duration=180] - Milliseconds.
|
|
310
|
+
* @param {string|((t: number) => number)} [options.easing="easeIn"] - Curve; an
|
|
311
|
+
* element leaving the screen at speed is the one place `easeIn` is right.
|
|
312
|
+
* @param {boolean} [options.fade=true] - Also animate `opacity` to 0.
|
|
313
|
+
* @returns {() => boolean} Cancel function.
|
|
314
|
+
*/
|
|
315
|
+
export const slideOut = (widget, options = {}) =>
|
|
316
|
+
play(widget, slideSteps({ direction: "down", ...options, leaving: true }));
|
|
317
|
+
|
|
318
|
+
/**
|
|
319
|
+
* The awaitable form of {@link slideOut} — the usual one, since what follows an
|
|
320
|
+
* exit is the unmount.
|
|
321
|
+
*
|
|
322
|
+
* @param {HTMLElement|object} widget - The target widget or DOM element.
|
|
323
|
+
* @param {object} [options] - See {@link slideOut}.
|
|
324
|
+
* @returns {Promise<HTMLElement|object>} Resolves with `widget` when it has left.
|
|
325
|
+
*/
|
|
326
|
+
export const slideOutAsync = (widget, options = {}) =>
|
|
327
|
+
playAsync(widget, slideSteps({ direction: "down", ...options, leaving: true }));
|
package/src/core/runApp.js
CHANGED
|
@@ -1,5 +1,4 @@
|
|
|
1
1
|
// core/runApp.js
|
|
2
|
-
import { stopWebRefresh } from "../utils/stopWebRefresh.js";
|
|
3
2
|
import { initRouter } from "../navigations/Router.js"; // ← IMPORTANT: add this line
|
|
4
3
|
import {
|
|
5
4
|
applySystemTheme,
|
|
@@ -38,11 +37,6 @@ export const runApp = (
|
|
|
38
37
|
const root = document.getElementById(rootId);
|
|
39
38
|
if (!root) return;
|
|
40
39
|
|
|
41
|
-
// If preventRefresh is true (default), we disable refreshes
|
|
42
|
-
// if (preventRefresh) {
|
|
43
|
-
// stopWebRefresh();
|
|
44
|
-
// }
|
|
45
|
-
|
|
46
40
|
let currentMainContainer = null;
|
|
47
41
|
let unsubscribeTheme = null;
|
|
48
42
|
let unwatchSystemTheme = null;
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
// helpers/boxEdges.js
|
|
2
|
+
/**
|
|
3
|
+
* @file boxEdges.js
|
|
4
|
+
* @description
|
|
5
|
+
* The one implementation behind `margin()` and `padding()`.
|
|
6
|
+
*
|
|
7
|
+
* CSS gives `margin` and `padding` the same four-value grammar, and the two
|
|
8
|
+
* helpers had drifted into two byte-identical copies of the side-resolution
|
|
9
|
+
* logic — 63 lines each, 25 branches each, differing only in the word in the
|
|
10
|
+
* JSDoc. A fix to the priority order or to the shorthand collapsing had to be
|
|
11
|
+
* made twice, so it is made here and both helpers delegate.
|
|
12
|
+
*
|
|
13
|
+
* Resolved per side, in priority order: the individual side, then its axis
|
|
14
|
+
* (`vertical` for top/bottom, `horizontal` for left/right), then `all`, then 0.
|
|
15
|
+
*
|
|
16
|
+
* @module helpers/boxEdges
|
|
17
|
+
*/
|
|
18
|
+
|
|
19
|
+
/** A number becomes a px string; anything else is already CSS and passes through. */
|
|
20
|
+
const px = (value) => (typeof value === "number" ? `${value}px` : value);
|
|
21
|
+
|
|
22
|
+
/**
|
|
23
|
+
* Resolves one side of the box from the options object.
|
|
24
|
+
*
|
|
25
|
+
* @param {Object} value - The options object.
|
|
26
|
+
* @param {string} side - `top`, `right`, `bottom` or `left`.
|
|
27
|
+
* @param {string} axis - `vertical` or `horizontal`.
|
|
28
|
+
* @returns {number|string} The raw side value; `0` when nothing applies.
|
|
29
|
+
*/
|
|
30
|
+
const sideOf = (value, side, axis) =>
|
|
31
|
+
value[side] !== undefined
|
|
32
|
+
? value[side]
|
|
33
|
+
: value[axis] !== undefined
|
|
34
|
+
? value[axis]
|
|
35
|
+
: value.all !== undefined
|
|
36
|
+
? value.all
|
|
37
|
+
: 0;
|
|
38
|
+
|
|
39
|
+
/**
|
|
40
|
+
* Builds the CSS box shorthand for a margin or a padding.
|
|
41
|
+
*
|
|
42
|
+
* One value when all four sides agree, two when only the axes differ, four
|
|
43
|
+
* otherwise. Callers are `margin()` and `padding()`; the value they receive is
|
|
44
|
+
* the same string CSS would have been handed had each side been written out.
|
|
45
|
+
*
|
|
46
|
+
* @param {number|string|Object} value
|
|
47
|
+
* A number (converted to `px`), a raw CSS string, or an options object with
|
|
48
|
+
* `all`, `horizontal`, `vertical` and per-side overrides.
|
|
49
|
+
* @returns {string} A CSS shorthand value.
|
|
50
|
+
*/
|
|
51
|
+
export const boxEdges = (value) => {
|
|
52
|
+
// A number or raw CSS string applies uniformly to all sides.
|
|
53
|
+
if (typeof value === "number" || typeof value === "string") return px(value);
|
|
54
|
+
|
|
55
|
+
if (typeof value === "object") {
|
|
56
|
+
const top = px(sideOf(value, "top", "vertical"));
|
|
57
|
+
const right = px(sideOf(value, "right", "horizontal"));
|
|
58
|
+
const bottom = px(sideOf(value, "bottom", "vertical"));
|
|
59
|
+
const left = px(sideOf(value, "left", "horizontal"));
|
|
60
|
+
|
|
61
|
+
if (top === right && right === bottom && bottom === left) return top;
|
|
62
|
+
if (top === bottom && right === left) return `${top} ${right}`;
|
|
63
|
+
return `${top} ${right} ${bottom} ${left}`;
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
return "0px";
|
|
67
|
+
};
|
|
68
|
+
|
|
69
|
+
export default boxEdges;
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @file html.js
|
|
3
|
+
* @description
|
|
4
|
+
* The one HTML escaper in the framework.
|
|
5
|
+
*
|
|
6
|
+
* Four modules build HTML strings — the Markdown widget, the Markdown parser,
|
|
7
|
+
* the syntax highlighter and the Markdown code renderer — and every one of them
|
|
8
|
+
* used to carry its own copy of the same five `replace()` calls. Three copies of
|
|
9
|
+
* a security boundary is three chances for one of them to be edited alone, so
|
|
10
|
+
* the implementation lives here: a leaf module with no imports, which matters
|
|
11
|
+
* because `utils/markdownParser.js` imports six widgets and anything that
|
|
12
|
+
* imported it from a widget would drag all six into that widget's graph.
|
|
13
|
+
*
|
|
14
|
+
* @module helpers/html
|
|
15
|
+
*/
|
|
16
|
+
|
|
17
|
+
/** The five characters that can end text or an attribute value early. */
|
|
18
|
+
const ENTITIES = {
|
|
19
|
+
"&": "&",
|
|
20
|
+
"<": "<",
|
|
21
|
+
">": ">",
|
|
22
|
+
'"': """,
|
|
23
|
+
"'": "'",
|
|
24
|
+
};
|
|
25
|
+
|
|
26
|
+
/**
|
|
27
|
+
* Escapes the characters that let text break out of an HTML context.
|
|
28
|
+
*
|
|
29
|
+
* A single pass over the source: `&` is replaced once and the entities it
|
|
30
|
+
* produces are not rescanned, so the output is safe to insert into element
|
|
31
|
+
* content and into a quoted attribute value.
|
|
32
|
+
*
|
|
33
|
+
* @param {string} text - Raw text.
|
|
34
|
+
* @returns {string} The same text with `& < > " '` replaced by entities.
|
|
35
|
+
*/
|
|
36
|
+
export const escapeHtml = (text) =>
|
|
37
|
+
String(text).replace(/[&<>"']/g, (char) => ENTITIES[char]);
|
|
38
|
+
|
|
39
|
+
export default escapeHtml;
|