flet-box 1.1.2 → 1.1.3
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/AGENTS_FOR_CODE_GEN.md +284 -0
- package/CONTRIBUTING.md +238 -0
- package/README.md +2 -2
- package/bin/cli.js +88 -1
- package/bin/commands/auditFix.js +181 -27
- package/bin/commands/checkApi.js +14 -3
- package/bin/commands/checkStructure.js +368 -0
- package/bin/commands/checkSyntax.js +293 -0
- package/bin/commands/checkUi.js +666 -14
- package/bin/commands/create.js +14 -0
- package/bin/commands/createBundle.js +2 -2
- package/bin/commands/metrics.js +448 -0
- package/bin/commands/release.js +18 -0
- package/bin/commands/report.js +849 -0
- package/bin/commands/tools.js +76 -0
- package/bin/commands/unpack.js +39 -11
- package/bin/commands/verify.js +879 -0
- package/bin/mcp.js +280 -0
- package/bin/utils/contract.js +27 -0
- package/bin/utils/dtsProps.js +5 -1
- package/bin/utils/migrationGuide.js +146 -0
- package/bin/utils/moduleExports.js +9 -5
- package/bin/utils/templates.js +225 -18
- package/bin/utils/toolkit.js +191 -0
- package/docs/README.md +5 -1
- package/docs/arquitectura.md +1 -1
- package/docs/cli/README.md +168 -2
- package/docs/guides/README.md +6 -0
- package/docs/guides/accessibility.md +2 -1
- package/docs/guides/ai-toolkit.md +166 -0
- package/docs/guides/compatibility.md +1 -1
- package/docs/guides/migration.md +92 -0
- package/docs/guides/minification-and-protection.md +2 -1
- package/docs/guides/mobile-and-platforms.md +1 -1
- package/docs/guides/online-updates.md +2 -0
- package/docs/server/deployment.md +1 -1
- package/docs/tools/styling.md +2 -2
- package/docs/tools/theme.md +139 -4
- package/docs/widget/Accordion.md +74 -8
- package/docs/widget/AdMob.md +68 -3
- package/docs/widget/AdSense.md +67 -2
- package/docs/widget/AlertDialog.md +1 -1
- package/docs/widget/AnimatedBox.md +80 -39
- package/docs/widget/AnimatedText.md +74 -18
- package/docs/widget/Audio.md +73 -14
- package/docs/widget/Avatar.md +69 -4
- package/docs/widget/Badge.md +68 -3
- package/docs/widget/BottomSheet.md +2 -2
- package/docs/widget/Button.md +69 -3
- package/docs/widget/Card.md +69 -4
- package/docs/widget/Carousel.md +67 -2
- package/docs/widget/Chart.md +67 -2
- package/docs/widget/Checkbox.md +74 -8
- package/docs/widget/Chip.md +68 -3
- package/docs/widget/CircularBar.md +74 -15
- package/docs/widget/CircularChart.md +71 -10
- package/docs/widget/CodeViewer.md +67 -2
- package/docs/widget/Column.md +68 -3
- package/docs/widget/Container.md +68 -3
- package/docs/widget/DataTable.md +67 -2
- package/docs/widget/Divider.md +67 -2
- package/docs/widget/DraggBox.md +67 -2
- package/docs/widget/Dropdown.md +76 -10
- package/docs/widget/DroppBox.md +67 -2
- package/docs/widget/FloatingActionButton.md +68 -3
- package/docs/widget/GridView.md +67 -2
- package/docs/widget/Icon.md +71 -5
- package/docs/widget/Image.md +68 -3
- package/docs/widget/Input.md +68 -3
- package/docs/widget/Inspector.md +2 -2
- package/docs/widget/InstallButton.md +73 -13
- package/docs/widget/ListTile.md +69 -3
- package/docs/widget/ListView.md +67 -2
- package/docs/widget/Maps.md +68 -3
- package/docs/widget/Markdown.md +74 -15
- package/docs/widget/MatrixRain.md +72 -11
- package/docs/widget/Menu.md +209 -0
- package/docs/widget/Modal.md +3 -3
- package/docs/widget/Pagination.md +68 -3
- package/docs/widget/ParallaxBox.md +72 -12
- package/docs/widget/ProgressBar.md +69 -4
- package/docs/widget/QRCode.md +67 -2
- package/docs/widget/README.md +54 -50
- package/docs/widget/Radio.md +76 -10
- package/docs/widget/Rating.md +70 -6
- package/docs/widget/Row.md +68 -3
- package/docs/widget/Skeleton.md +68 -3
- package/docs/widget/Slider.md +75 -9
- package/docs/widget/SnackBar.md +2 -2
- package/docs/widget/Stack.md +68 -3
- package/docs/widget/Stepper.md +68 -3
- package/docs/widget/Switch.md +74 -8
- package/docs/widget/Text.md +71 -4
- package/docs/widget/ThemePicker.md +197 -0
- package/docs/widget/Tooltip.md +72 -7
- package/docs/widget/TreeView.md +70 -10
- package/docs/widget/Video.md +71 -10
- package/package.json +10 -3
- package/skills/fletbox-design/SKILL.md +89 -5
- package/skills/fletbox-motion/SKILL.md +1 -1
- package/skills/fletbox-rules/SKILL.md +56 -4
- package/src/core/runApp.js +12 -0
- package/src/index.d.ts +374 -101
- package/src/index.js +9 -0
- package/src/navigations/AdaptiveScaffold.js +2 -2
- package/src/navigations/BottomNavigation.js +1 -1
- package/src/navigations/Scaffold.js +18 -6
- package/src/tools/useState.js +11 -4
- package/src/utils/colors.js +275 -0
- package/src/utils/errorBoundary.js +288 -0
- package/src/utils/index.js +10 -2
- package/src/utils/stackPosition.js +39 -24
- package/src/utils/syntaxHighlight.js +4 -1
- package/src/utils/themes.js +279 -3
- package/src/widget-factory/addChildren.js +17 -10
- package/src/widget-factory/assignProps.js +18 -6
- package/src/widget-factory/createWidget.js +7 -0
- package/src/widget-factory/deprecations.js +77 -0
- package/src/widget-factory/translateProps.js +11 -1
- package/src/widget-factory/warnings.js +1 -27
- package/src/widget-factory/widgetFactory.js +59 -17
- package/src/widgets/Accordion.js +21 -7
- package/src/widgets/Badge.js +11 -2
- package/src/widgets/Button.js +15 -3
- package/src/widgets/Carousel.js +12 -4
- package/src/widgets/Chart.js +7 -2
- package/src/widgets/Checkbox.js +1 -2
- package/src/widgets/Chip.js +24 -10
- package/src/widgets/CircularBar.js +9 -3
- package/src/widgets/CircularChart.js +5 -3
- package/src/widgets/Container.js +6 -0
- package/src/widgets/Divider.js +3 -1
- package/src/widgets/DraggBox.js +9 -0
- package/src/widgets/Dropdown.js +3 -3
- package/src/widgets/DroppBox.js +5 -0
- package/src/widgets/FloatingActionButton.js +1 -1
- package/src/widgets/Icon.js +5 -1
- package/src/widgets/InstallButton.js +4 -2
- package/src/widgets/Markdown.js +171 -103
- package/src/widgets/Menu.js +340 -0
- package/src/widgets/Modal.js +7 -1
- package/src/widgets/Pagination.js +10 -5
- package/src/widgets/ProgressBar.js +5 -4
- package/src/widgets/QRCode.js +4 -0
- package/src/widgets/Radio.js +1 -2
- package/src/widgets/Rating.js +9 -0
- package/src/widgets/Slider.js +4 -1
- package/src/widgets/SnackBar.js +2 -2
- package/src/widgets/Switch.js +1 -2
- package/src/widgets/Text.js +9 -5
- package/src/widgets/ThemePicker.js +234 -0
- package/src/widgets/TreeView.js +2 -1
- package/src/widgets/index.js +2 -0
- package/docs/CONTRIBUTING.md +0 -156
|
@@ -0,0 +1,288 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @file errorBoundary.js
|
|
3
|
+
* @description
|
|
4
|
+
* The wall that keeps one broken widget from taking the whole screen with it.
|
|
5
|
+
*
|
|
6
|
+
* A FletBox app is a tree of DOM nodes built by factories. A throw inside one
|
|
7
|
+
* of them — a prop that reads something undefined, a callback that assumes a
|
|
8
|
+
* shape the data no longer has — used to travel straight out of the factory,
|
|
9
|
+
* out of the component, out of `renderApp`, and leave the root empty: a white
|
|
10
|
+
* page, a red line in the console, and nothing on the screen to say where it
|
|
11
|
+
* went. The person saw a blank app; the developer saw a stack trace with no
|
|
12
|
+
* hint of which widget was on screen at the time.
|
|
13
|
+
*
|
|
14
|
+
* This module is that missing wall, in the three places a throw can escape:
|
|
15
|
+
*
|
|
16
|
+
* 1. **the factory** catches a throw while it builds or updates a widget, and
|
|
17
|
+
* the widget paints a placeholder in its own place — the rest of the
|
|
18
|
+
* screen keeps working;
|
|
19
|
+
* 2. **the app render** catches a throw that happened outside any widget, and
|
|
20
|
+
* the root paints the placeholder instead of staying empty;
|
|
21
|
+
* 3. **a handler** is wrapped where it is attached, so a throw inside an
|
|
22
|
+
* `onPress` is reported with the name of the widget that owns it.
|
|
23
|
+
*
|
|
24
|
+
* The placeholder is written with theme tokens and never with hard-coded
|
|
25
|
+
* colors, and it is announced (`role="alert"`): a broken widget is still
|
|
26
|
+
* information the person on the other side needs, and a silent empty box is
|
|
27
|
+
* how a blank screen becomes a mystery.
|
|
28
|
+
*
|
|
29
|
+
* Nothing here swallows an error. The global handler reports it and lets the
|
|
30
|
+
* browser report it too — the boundary adds context, it does not hide.
|
|
31
|
+
*
|
|
32
|
+
* @module errorBoundary
|
|
33
|
+
*/
|
|
34
|
+
|
|
35
|
+
import { colors } from "./themes.js";
|
|
36
|
+
import { toREM } from "./units.js";
|
|
37
|
+
|
|
38
|
+
/**
|
|
39
|
+
* The attribute a failed widget carries, so a harness, an inspector or a test
|
|
40
|
+
* can find the failure without reading the console.
|
|
41
|
+
*
|
|
42
|
+
* @type {string}
|
|
43
|
+
*/
|
|
44
|
+
export const FAILURE_ATTR = "data-fb-error";
|
|
45
|
+
|
|
46
|
+
/**
|
|
47
|
+
* The last failure the boundary saw. A harness reads it to assert *what* was
|
|
48
|
+
* reported, not only that something was painted.
|
|
49
|
+
*
|
|
50
|
+
* @type {{error: Error, message: string, widgetName: string|null, phase: string, event: string|null, source: string|null, when: string}|null}
|
|
51
|
+
*/
|
|
52
|
+
let lastFailure = null;
|
|
53
|
+
|
|
54
|
+
/**
|
|
55
|
+
* The placeholder's own styles. Every length is a framework unit through
|
|
56
|
+
* `toREM`, so the note grows with the reader's font like the rest of the page,
|
|
57
|
+
* and every color is a theme token, so it follows the theme it is painted in.
|
|
58
|
+
*
|
|
59
|
+
* The ink is the page's own `text` and not the red: on the error tint the red
|
|
60
|
+
* measures 3.49:1 in the light theme, which is a rim and not a word. The rim
|
|
61
|
+
* carries the "this went wrong" and the text stays readable.
|
|
62
|
+
*/
|
|
63
|
+
const PLACEHOLDER_CSS = `
|
|
64
|
+
display: flex;
|
|
65
|
+
flex-direction: column;
|
|
66
|
+
gap: ${toREM(4)};
|
|
67
|
+
padding: ${toREM(12)};
|
|
68
|
+
border-radius: ${toREM(8)};
|
|
69
|
+
border: 1px solid var(--color-error, ${colors.error});
|
|
70
|
+
background: var(--color-errorBg, ${colors.errorBg});
|
|
71
|
+
color: var(--color-text, ${colors.text});
|
|
72
|
+
font-size: ${toREM(14)};
|
|
73
|
+
line-height: 1.4;
|
|
74
|
+
overflow-wrap: anywhere;
|
|
75
|
+
`;
|
|
76
|
+
|
|
77
|
+
/**
|
|
78
|
+
* Reports a failure with the context that makes it actionable.
|
|
79
|
+
*
|
|
80
|
+
* The console line names the widget, the phase and the message; the original
|
|
81
|
+
* error is passed along so the stack stays clickable. The failure is also
|
|
82
|
+
* remembered, because a screen that shows a placeholder must be able to say
|
|
83
|
+
* *why* without the developer hunting through the console.
|
|
84
|
+
*
|
|
85
|
+
* @param {Error|unknown} error - What was thrown.
|
|
86
|
+
* @param {Object} [context={}] - Where it happened.
|
|
87
|
+
* @param {string} [context.widgetName] - The widget that owns the failure.
|
|
88
|
+
* @param {string} [context.phase] - `render`, `update`, `handler`, `app`…
|
|
89
|
+
* @param {string} [context.event] - The event name, when a handler threw.
|
|
90
|
+
* @param {string} [context.source] - `file:line`, when the browser reported it.
|
|
91
|
+
* @returns {Object} The recorded failure.
|
|
92
|
+
*/
|
|
93
|
+
export function reportFailure(error, context = {}) {
|
|
94
|
+
const message =
|
|
95
|
+
error && typeof error.message === "string" && error.message
|
|
96
|
+
? error.message
|
|
97
|
+
: String(error);
|
|
98
|
+
|
|
99
|
+
lastFailure = {
|
|
100
|
+
error,
|
|
101
|
+
message,
|
|
102
|
+
widgetName: context.widgetName || null,
|
|
103
|
+
phase: context.phase || "unknown",
|
|
104
|
+
event: context.event || null,
|
|
105
|
+
source: context.source || null,
|
|
106
|
+
when: new Date().toISOString(),
|
|
107
|
+
};
|
|
108
|
+
|
|
109
|
+
const whose = lastFailure.widgetName ? lastFailure.widgetName : "the app";
|
|
110
|
+
const where = lastFailure.event
|
|
111
|
+
? `${whose} failed in its ${lastFailure.event} handler`
|
|
112
|
+
: `${whose} failed during ${lastFailure.phase}`;
|
|
113
|
+
|
|
114
|
+
console.error(`[FletBox] ${where}: ${message}`, error);
|
|
115
|
+
return lastFailure;
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
/**
|
|
119
|
+
* The last failure the boundary saw, or `null`.
|
|
120
|
+
*
|
|
121
|
+
* @returns {Object|null} The recorded failure.
|
|
122
|
+
*/
|
|
123
|
+
export function getLastFailure() {
|
|
124
|
+
return lastFailure;
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
/**
|
|
128
|
+
* Paints the placeholder that stands in for a widget that could not be built.
|
|
129
|
+
*
|
|
130
|
+
* The placeholder goes *inside* the host, so the widget keeps its place in the
|
|
131
|
+
* layout: a broken card is a card that says so, not a hole where a card was.
|
|
132
|
+
* The host's own content is cleared first — a half-built widget is worse than
|
|
133
|
+
* an empty one, because it looks finished.
|
|
134
|
+
*
|
|
135
|
+
* The host is the element that carries the marker, so one failure is one
|
|
136
|
+
* marked element and the placeholder inside it is found by its role.
|
|
137
|
+
*
|
|
138
|
+
* @param {HTMLElement} host - The widget (or the app root) that failed.
|
|
139
|
+
* @param {Object} failure - The recorded failure.
|
|
140
|
+
* @param {Object} [context={}] - Where it happened.
|
|
141
|
+
* @returns {HTMLElement|null} The placeholder, or `null` outside a browser.
|
|
142
|
+
*/
|
|
143
|
+
export function paintFailure(host, failure, context = {}) {
|
|
144
|
+
if (!host || typeof document === "undefined") return null;
|
|
145
|
+
|
|
146
|
+
const phase = context.phase || "render";
|
|
147
|
+
|
|
148
|
+
const box = document.createElement("div");
|
|
149
|
+
box.setAttribute("role", "alert");
|
|
150
|
+
box.style.cssText = PLACEHOLDER_CSS;
|
|
151
|
+
|
|
152
|
+
const title = document.createElement("strong");
|
|
153
|
+
title.textContent = context.widgetName
|
|
154
|
+
? `${context.widgetName} could not be rendered`
|
|
155
|
+
: "This screen could not be rendered";
|
|
156
|
+
|
|
157
|
+
const detail = document.createElement("span");
|
|
158
|
+
detail.textContent = failure.message;
|
|
159
|
+
|
|
160
|
+
box.appendChild(title);
|
|
161
|
+
box.appendChild(detail);
|
|
162
|
+
|
|
163
|
+
while (host.firstChild) host.removeChild(host.firstChild);
|
|
164
|
+
host.appendChild(box);
|
|
165
|
+
host.setAttribute(FAILURE_ATTR, phase);
|
|
166
|
+
host._failureBox = box;
|
|
167
|
+
return box;
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
/**
|
|
171
|
+
* Reports a failure and paints the placeholder in its place.
|
|
172
|
+
*
|
|
173
|
+
* @param {HTMLElement} host - The widget (or the app root) that failed.
|
|
174
|
+
* @param {Error|unknown} error - What was thrown.
|
|
175
|
+
* @param {Object} [context={}] - Where it happened.
|
|
176
|
+
* @returns {HTMLElement|null} The placeholder, or `null` outside a browser.
|
|
177
|
+
*/
|
|
178
|
+
export function renderFailure(host, error, context = {}) {
|
|
179
|
+
if (!host || typeof document === "undefined") return null;
|
|
180
|
+
const failure = reportFailure(error, context);
|
|
181
|
+
return paintFailure(host, failure, context);
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
/**
|
|
185
|
+
* Removes the placeholder a previous failure painted, so a later successful
|
|
186
|
+
* update can put the real content back.
|
|
187
|
+
*
|
|
188
|
+
* @param {HTMLElement} host - The widget that may carry a placeholder.
|
|
189
|
+
* @returns {void}
|
|
190
|
+
*/
|
|
191
|
+
export function clearFailure(host) {
|
|
192
|
+
if (!host) return;
|
|
193
|
+
if (host._failureBox && host._failureBox.parentNode === host) {
|
|
194
|
+
host._failureBox.remove();
|
|
195
|
+
}
|
|
196
|
+
host._failureBox = null;
|
|
197
|
+
host.removeAttribute(FAILURE_ATTR);
|
|
198
|
+
}
|
|
199
|
+
|
|
200
|
+
/**
|
|
201
|
+
* Wraps an event handler so a throw inside it is caught with the name of the
|
|
202
|
+
* widget that owns it.
|
|
203
|
+
*
|
|
204
|
+
* Without this, an `onPress` that throws reaches `window.onerror` as an
|
|
205
|
+
* anonymous stack: the developer learns that *something* threw and has to
|
|
206
|
+
* guess which control. Here the console names the widget.
|
|
207
|
+
*
|
|
208
|
+
* @param {Function} handler - The handler to protect.
|
|
209
|
+
* @param {Object} [context={}] - Where it happened.
|
|
210
|
+
* @returns {Function} The protected handler.
|
|
211
|
+
*/
|
|
212
|
+
export function guardHandler(handler, context = {}) {
|
|
213
|
+
if (typeof handler !== "function") return handler;
|
|
214
|
+
return (event) => {
|
|
215
|
+
try {
|
|
216
|
+
return handler(event);
|
|
217
|
+
} catch (error) {
|
|
218
|
+
reportFailure(error, {
|
|
219
|
+
...context,
|
|
220
|
+
phase: "handler",
|
|
221
|
+
event: (event && event.type) || context.event || null,
|
|
222
|
+
});
|
|
223
|
+
return undefined;
|
|
224
|
+
}
|
|
225
|
+
};
|
|
226
|
+
}
|
|
227
|
+
|
|
228
|
+
/**
|
|
229
|
+
* Installs the global handler: the last wall, for the errors no widget owns.
|
|
230
|
+
*
|
|
231
|
+
* A rejected promise and an error thrown from a timer never reach a widget,
|
|
232
|
+
* so nothing above can catch them. This reports them with whatever context the
|
|
233
|
+
* browser carries (the file and the line) and leaves the browser's own report
|
|
234
|
+
* in place — `preventDefault()` is not called, because an error that nobody
|
|
235
|
+
* can see is worse than a noisy console.
|
|
236
|
+
*
|
|
237
|
+
* Calling it twice installs one handler: the second call returns the same
|
|
238
|
+
* disposer.
|
|
239
|
+
*
|
|
240
|
+
* @param {Object} [options={}] - Optional `onError(error, context)` hook.
|
|
241
|
+
* @returns {Function|null} A disposer, or `null` outside a browser.
|
|
242
|
+
*/
|
|
243
|
+
export function installErrorBoundary(options = {}) {
|
|
244
|
+
if (typeof window === "undefined" || !window.addEventListener) return null;
|
|
245
|
+
if (installErrorBoundary._release) return installErrorBoundary._release;
|
|
246
|
+
|
|
247
|
+
const onError = (event) => {
|
|
248
|
+
// A resource that failed to load (an image, a font) also arrives here, and
|
|
249
|
+
// it is not a thrown error: it has no stack and it is not a bug in the app.
|
|
250
|
+
if (!event.error && !event.filename) return;
|
|
251
|
+
|
|
252
|
+
const error = event.error || new Error(event.message || "Unknown error");
|
|
253
|
+
const context = {
|
|
254
|
+
phase: "global",
|
|
255
|
+
source: event.filename ? `${event.filename}:${event.lineno}` : null,
|
|
256
|
+
};
|
|
257
|
+
const failure = reportFailure(error, context);
|
|
258
|
+
if (typeof options.onError === "function") options.onError(error, failure);
|
|
259
|
+
};
|
|
260
|
+
|
|
261
|
+
const onRejection = (event) => {
|
|
262
|
+
const reason = event.reason;
|
|
263
|
+
const error = reason instanceof Error ? reason : new Error(String(reason));
|
|
264
|
+
const failure = reportFailure(error, { phase: "rejection" });
|
|
265
|
+
if (typeof options.onError === "function") options.onError(error, failure);
|
|
266
|
+
};
|
|
267
|
+
|
|
268
|
+
window.addEventListener("error", onError);
|
|
269
|
+
window.addEventListener("unhandledrejection", onRejection);
|
|
270
|
+
|
|
271
|
+
installErrorBoundary._release = () => {
|
|
272
|
+
window.removeEventListener("error", onError);
|
|
273
|
+
window.removeEventListener("unhandledrejection", onRejection);
|
|
274
|
+
installErrorBoundary._release = null;
|
|
275
|
+
};
|
|
276
|
+
return installErrorBoundary._release;
|
|
277
|
+
}
|
|
278
|
+
|
|
279
|
+
export default {
|
|
280
|
+
FAILURE_ATTR,
|
|
281
|
+
reportFailure,
|
|
282
|
+
getLastFailure,
|
|
283
|
+
paintFailure,
|
|
284
|
+
renderFailure,
|
|
285
|
+
clearFailure,
|
|
286
|
+
guardHandler,
|
|
287
|
+
installErrorBoundary,
|
|
288
|
+
};
|
package/src/utils/index.js
CHANGED
|
@@ -10,12 +10,13 @@
|
|
|
10
10
|
* ```
|
|
11
11
|
*
|
|
12
12
|
* Included utilities:
|
|
13
|
-
* - **themes** — color palette, theme switching, CSS variable sync
|
|
13
|
+
* - **themes** — color palette, theme switching, CSS variable sync,
|
|
14
|
+
* accent presets (a hue family painted over the palette)
|
|
14
15
|
* - **getWidgetProps** — read widget `_props` safely
|
|
15
16
|
* - **syntaxHighlight** — JavaScript/FletBox tokenizer and HTML highlighter
|
|
16
17
|
* - **markdownParser** — markdown → FletBox widget tree converter
|
|
17
18
|
* - **visualEffects** — CSS animations (stripes, shimmer, glow, pulse)
|
|
18
|
-
* - **stackPosition** —
|
|
19
|
+
* - **stackPosition** — absolute positioning for a widget layered over its parent
|
|
19
20
|
* - **units** — px ↔ rem conversion helpers
|
|
20
21
|
* - **navigation** — tree-navigation mixin for widget objects
|
|
21
22
|
* - **stopWebRefresh** — disables browser refresh gestures
|
|
@@ -26,6 +27,13 @@ export {
|
|
|
26
27
|
colors,
|
|
27
28
|
setTheme,
|
|
28
29
|
registerPalette,
|
|
30
|
+
registerAccent,
|
|
31
|
+
setAccent,
|
|
32
|
+
applyAccentPreference,
|
|
33
|
+
getAccent,
|
|
34
|
+
getAccentSurfaces,
|
|
35
|
+
listAccents,
|
|
36
|
+
listAccentRamps,
|
|
29
37
|
getTheme,
|
|
30
38
|
toggleTheme,
|
|
31
39
|
subscribeTheme,
|
|
@@ -1,31 +1,46 @@
|
|
|
1
1
|
// utils/stackPosition.js
|
|
2
|
-
|
|
3
2
|
/**
|
|
4
|
-
*
|
|
5
|
-
*
|
|
6
|
-
*
|
|
3
|
+
* @file stackPosition.js
|
|
4
|
+
* @description Anchors a widget over its positioned ancestor — the public, call
|
|
5
|
+
* it-yourself form of what `position: "stack"` does inside the factory.
|
|
6
|
+
*
|
|
7
|
+
* The helper used to write `top`, `right`, `bottom` and `left` into the element's
|
|
8
|
+
* `dataset` "so that a parent Stack can read it later". No parent ever read it:
|
|
9
|
+
* `Stack` layers its children with one stylesheet rule (`stackLayout.js`), and
|
|
10
|
+
* nothing in the framework looks at `data-top`. So the call the docs, the snippet
|
|
11
|
+
* library and the design skill all recommend —
|
|
12
|
+
* `stackPosition(badge, { top: 8, right: 8 })` — returned the widget with its
|
|
13
|
+
* edges recorded and its position untouched, which is worse than an error: the
|
|
14
|
+
* overlay simply stayed where the flow had put it.
|
|
15
|
+
*
|
|
16
|
+
* It now delegates to the engine's own implementation, so there is one set of
|
|
17
|
+
* rules for edges, centring and the rem contract rather than two that drift. The
|
|
18
|
+
* engine gates on `position: "stack"` because it sees every prop of every widget
|
|
19
|
+
* and must not treat an unrelated `top` as a placement; an explicit call to this
|
|
20
|
+
* helper *is* the intent to place, so it passes that gate itself.
|
|
7
21
|
*
|
|
8
|
-
* @
|
|
9
|
-
* @param {Object} props - Props object that may contain `top`, `right`, `bottom`, and/or `left`.
|
|
10
|
-
* @param {number|string} [props.top] - Distance from the top edge (px or CSS string).
|
|
11
|
-
* @param {number|string} [props.right] - Distance from the right edge (px or CSS string).
|
|
12
|
-
* @param {number|string} [props.bottom] - Distance from the bottom edge (px or CSS string).
|
|
13
|
-
* @param {number|string} [props.left] - Distance from the left edge (px or CSS string).
|
|
14
|
-
* @returns {HTMLElement} The same `widget` reference, with dataset attributes set.
|
|
22
|
+
* @module stackPosition
|
|
15
23
|
*/
|
|
16
|
-
|
|
17
|
-
const top = props.top;
|
|
18
|
-
const right = props.right;
|
|
19
|
-
const bottom = props.bottom;
|
|
20
|
-
const left = props.left;
|
|
24
|
+
import { stackPosition as placeInStack } from "../widget-factory/stackPosition.js";
|
|
21
25
|
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
}
|
|
26
|
+
/**
|
|
27
|
+
* Absolutely position a widget relative to its nearest positioned ancestor.
|
|
28
|
+
*
|
|
29
|
+
* Numbers follow the framework-wide unit contract: they are pixels on the base
|
|
30
|
+
* font size and are emitted as `rem`, so an overlay moves with the reader's text
|
|
31
|
+
* size instead of freezing at the pixel it was written in.
|
|
32
|
+
*
|
|
33
|
+
* @param {HTMLElement} widget - The widget to anchor. Returned unchanged.
|
|
34
|
+
* @param {Object} [props] - Any of `top`, `right`, `bottom`, `left`, `start`,
|
|
35
|
+
* `end`, `centerX`, `centerY`, `center`, `fullWidth`, `fullHeight`, `full`.
|
|
36
|
+
* A value of `false` means "do not apply".
|
|
37
|
+
* @returns {HTMLElement} The same `widget`, now positioned.
|
|
38
|
+
*
|
|
39
|
+
* @example
|
|
40
|
+
* const badge = Icon({ name: "notifications" });
|
|
41
|
+
* stackPosition(badge, { top: 8, right: 8 }); // → position:absolute; top:.5rem; right:.5rem
|
|
42
|
+
*/
|
|
43
|
+
export const stackPosition = (widget, props = {}) =>
|
|
44
|
+
placeInStack(widget, { ...props, position: "stack" });
|
|
30
45
|
|
|
31
46
|
export default stackPosition;
|
|
@@ -156,7 +156,10 @@ const LIGHT_HIGHLIGHT_COLORS = {
|
|
|
156
156
|
[TokenType.NUMBER]: "#0550ae", // blue
|
|
157
157
|
[TokenType.COMMENT]: "#57606a", // gray
|
|
158
158
|
[TokenType.PROPERTY]: "#953800", // brown
|
|
159
|
-
|
|
159
|
+
// `#8250df` clears AA on the framework's own #fafafa pane by 0.33 and fails
|
|
160
|
+
// one on a slightly darker app plate (#eef2f7 → 4.49). `#6f42c1` is the same
|
|
161
|
+
// GitHub purple a step deeper: 5.79 there, and 6.51 on white.
|
|
162
|
+
[TokenType.FUNCTION]: "#6f42c1", // purple
|
|
160
163
|
[TokenType.BRACKET]: "#57606a", // gray
|
|
161
164
|
[TokenType.PUNCTUATION]: "#57606a", // gray
|
|
162
165
|
[TokenType.FLETBOX_COLOR]: "#0e7490", // teal
|