flexdesk 0.17.4 → 0.17.6
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/CHANGELOG.md +36 -0
- package/dist/charts.js +20 -3
- package/dist/charts.js.map +2 -2
- package/dist/editor.js +12 -0
- package/dist/editor.js.map +2 -2
- package/docs/components/charts.md +24 -0
- package/docs/components/editor.md +21 -0
- package/package.json +1 -1
- package/src/charts/data_series_plot_window.js +17 -3
- package/src/editor/monaco_editor_factory.js +7 -1
- package/src/editor/monaco_loader.js +37 -0
|
@@ -107,7 +107,8 @@ class DataSeriesPlotWindow {
|
|
|
107
107
|
this._config = { ...saved };
|
|
108
108
|
this._config.yColumns = (saved.yColumns || []).filter(c => this._numericColumns.has(c.header));
|
|
109
109
|
} else {
|
|
110
|
-
this._config = DataSeriesPlotWindow.createDefaultConfig(
|
|
110
|
+
this._config = DataSeriesPlotWindow.createDefaultConfig(
|
|
111
|
+
this.headers, this._numericColumns, this.classifyHeader);
|
|
111
112
|
}
|
|
112
113
|
|
|
113
114
|
this.#createWindow();
|
|
@@ -694,13 +695,26 @@ class DataSeriesPlotWindow {
|
|
|
694
695
|
|
|
695
696
|
// ── Default config factory ───────────────────────────────────────────
|
|
696
697
|
|
|
697
|
-
|
|
698
|
+
/**
|
|
699
|
+
* The config a series with no saved one opens with: the first numeric
|
|
700
|
+
* column `classifyHeader` calls `'time'` is X (else the first numeric
|
|
701
|
+
* column), and up to MAX_AUTO_COLUMNS other numeric columns are Y.
|
|
702
|
+
*
|
|
703
|
+
* Static, so it has no window: the header classifier is a parameter. A
|
|
704
|
+
* window passes its own (`options.classifyHeader`); a caller that passes
|
|
705
|
+
* none gets the default, which knows `t`/`time`/`step`/`period`.
|
|
706
|
+
*
|
|
707
|
+
* @param {string[]} headers
|
|
708
|
+
* @param {Set<string>} [numericColumns] - absent => every column is numeric
|
|
709
|
+
* @param {(header: string) => string} [classifyHeader=defaultClassifyHeader]
|
|
710
|
+
*/
|
|
711
|
+
static createDefaultConfig(headers, numericColumns, classifyHeader = defaultClassifyHeader) {
|
|
698
712
|
const isNumeric = numericColumns instanceof Set ? (h) => numericColumns.has(h) : () => true;
|
|
699
713
|
|
|
700
714
|
// Find best X column (time-like, must be numeric)
|
|
701
715
|
let xColumn = '';
|
|
702
716
|
for (const h of headers) {
|
|
703
|
-
if (isNumeric(h) &&
|
|
717
|
+
if (isNumeric(h) && classifyHeader(h) === 'time') {
|
|
704
718
|
xColumn = h;
|
|
705
719
|
break;
|
|
706
720
|
}
|
|
@@ -22,7 +22,13 @@ export function setDefaultLanguage(id) {
|
|
|
22
22
|
if (typeof id === 'string' && id) _defaultLanguage = id;
|
|
23
23
|
}
|
|
24
24
|
|
|
25
|
-
/**
|
|
25
|
+
/**
|
|
26
|
+
* Dispose a Monaco editor, swallowing a "Canceled" error that `dispose()` throws
|
|
27
|
+
* synchronously. It cannot catch the asynchronous kind — a pending Delayer's
|
|
28
|
+
* promise rejected by the dispose, which surfaces later as an unhandled
|
|
29
|
+
* rejection; the loader's window listener hides those (see
|
|
30
|
+
* `installCancellationGuard` in monaco_loader.js, BUG-0038).
|
|
31
|
+
*/
|
|
26
32
|
function safeDispose(editor) {
|
|
27
33
|
try { editor.dispose(); } catch (e) { if (e?.message !== 'Canceled') throw e; }
|
|
28
34
|
}
|
|
@@ -38,6 +38,38 @@ let _attempt = null;
|
|
|
38
38
|
*/
|
|
39
39
|
export const monacoReady = new Promise(resolve => { _resolveMonaco = resolve; });
|
|
40
40
|
|
|
41
|
+
/**
|
|
42
|
+
* Monaco's asynchronous CancellationError is benign; keep it off the page.
|
|
43
|
+
*
|
|
44
|
+
* Monaco starts timers it never awaits: its WordHighlighter calls
|
|
45
|
+
* `runDelayer.trigger()` (a 50 ms Delayer) when an editor gets focus and
|
|
46
|
+
* drops the promise. Dispose the editor inside those 50 ms and
|
|
47
|
+
* `Delayer.dispose() -> cancel()` rejects that promise with a CancellationError
|
|
48
|
+
* (name and message both 'Canceled') that nothing handles, so the browser
|
|
49
|
+
* reports an uncaught 'Canceled' (BUG-0038). VS Code hides these with its own
|
|
50
|
+
* unhandledrejection handler; standalone Monaco has none, so FlexDesk installs
|
|
51
|
+
* one here: it calls preventDefault() for exactly that error and leaves every
|
|
52
|
+
* other rejection to surface as before.
|
|
53
|
+
*
|
|
54
|
+
* Installed once per page, by the first initMonaco() that starts a load, and
|
|
55
|
+
* kept for the life of the page — like Monaco itself, which cannot be unloaded.
|
|
56
|
+
*/
|
|
57
|
+
let _cancellationGuardInstalled = false;
|
|
58
|
+
|
|
59
|
+
function isMonacoCancellation(reason) {
|
|
60
|
+
return reason?.name === 'Canceled' && reason?.message === 'Canceled';
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
function installCancellationGuard() {
|
|
64
|
+
if (_cancellationGuardInstalled) return;
|
|
65
|
+
_cancellationGuardInstalled = true;
|
|
66
|
+
// `?.`: the loader suites' stand-in pages (tests/monaco_env.mjs and the
|
|
67
|
+
// suites that set `window = globalThis` under Node) have no event target.
|
|
68
|
+
window.addEventListener?.('unhandledrejection', (event) => {
|
|
69
|
+
if (isMonacoCancellation(event.reason)) event.preventDefault();
|
|
70
|
+
});
|
|
71
|
+
}
|
|
72
|
+
|
|
41
73
|
function injectLoaderScript(src) {
|
|
42
74
|
return new Promise((resolve, reject) => {
|
|
43
75
|
const s = document.createElement('script');
|
|
@@ -124,6 +156,10 @@ async function loadMonaco(basePath) {
|
|
|
124
156
|
* given). An AMD-level failure is final for the page: every later call gets
|
|
125
157
|
* the same rejection, and only a reload recovers (see `_attempt`).
|
|
126
158
|
*
|
|
159
|
+
* The first call that starts a load also installs one window
|
|
160
|
+
* 'unhandledrejection' listener that hides Monaco's benign asynchronous
|
|
161
|
+
* CancellationError, and nothing else (see `installCancellationGuard`).
|
|
162
|
+
*
|
|
127
163
|
* @param {string} [basePath] Path prefix for the vs/ directory. REQUIRED
|
|
128
164
|
* unless an attempt is already in flight or has succeeded.
|
|
129
165
|
* @returns {Promise<typeof monaco>}
|
|
@@ -136,6 +172,7 @@ export function initMonaco(basePath) {
|
|
|
136
172
|
+ "initMonaco('vendor/monaco'). Monaco is a peer dependency; the library "
|
|
137
173
|
+ 'does not guess where you put it.'));
|
|
138
174
|
}
|
|
175
|
+
installCancellationGuard();
|
|
139
176
|
const attempt = loadMonaco(basePath).then(
|
|
140
177
|
(m) => { _resolveMonaco(m); return m; },
|
|
141
178
|
(err) => {
|