flexdesk 0.17.7 → 0.17.9
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 +43 -0
- package/LICENSE +0 -0
- package/README.md +0 -0
- package/THIRD_PARTY_LICENSES.md +0 -0
- package/canvas.js +0 -0
- package/charts.js +0 -0
- package/core.js +0 -0
- package/css/base.css +21 -1
- package/css/flexdesk.css +30 -3
- package/css/overrides.css +0 -0
- package/css/reset.css +0 -0
- package/dist/canvas.js +0 -0
- package/dist/canvas.js.map +0 -0
- package/dist/charts.js +7 -6
- package/dist/charts.js.map +2 -2
- package/dist/{chunk-RMTRWWEO.js → chunk-2YTM3GJE.js} +67 -26
- package/dist/chunk-2YTM3GJE.js.map +7 -0
- package/dist/chunk-3PHCPZHT.js +0 -0
- package/dist/chunk-3PHCPZHT.js.map +0 -0
- package/dist/{chunk-UURZ37SD.js → chunk-7U4IB65H.js} +27 -9
- package/dist/chunk-7U4IB65H.js.map +7 -0
- package/dist/{chunk-D3COLZZ2.js → chunk-BE2PU3LL.js} +2 -2
- package/dist/{chunk-D3COLZZ2.js.map → chunk-BE2PU3LL.js.map} +0 -0
- package/dist/chunk-CVMCZZX2.js +0 -0
- package/dist/chunk-CVMCZZX2.js.map +0 -0
- package/dist/{chunk-UWO43BZU.js → chunk-F35XSQWA.js} +16 -20
- package/dist/chunk-F35XSQWA.js.map +7 -0
- package/dist/chunk-FOOS3T5L.js +0 -0
- package/dist/chunk-FOOS3T5L.js.map +0 -0
- package/dist/chunk-GOQLR5WR.js +0 -0
- package/dist/chunk-GOQLR5WR.js.map +0 -0
- package/dist/chunk-HNU6MM2B.js +0 -0
- package/dist/chunk-HNU6MM2B.js.map +0 -0
- package/dist/chunk-JKZLNKG6.js +0 -0
- package/dist/chunk-JKZLNKG6.js.map +0 -0
- package/dist/chunk-JYWURG5T.js +0 -0
- package/dist/chunk-JYWURG5T.js.map +0 -0
- package/dist/{chunk-RKNFBX5K.js → chunk-MIW7D6WC.js} +16 -4
- package/dist/{chunk-RKNFBX5K.js.map → chunk-MIW7D6WC.js.map} +2 -2
- package/dist/chunk-N7HC3ADV.js +0 -0
- package/dist/chunk-N7HC3ADV.js.map +0 -0
- package/dist/{chunk-LWV23YVE.js → chunk-NIJEJAZ7.js} +42 -18
- package/dist/chunk-NIJEJAZ7.js.map +7 -0
- package/dist/{chunk-HYJYYEPK.js → chunk-REJ5HLIM.js} +2 -2
- package/dist/{chunk-HYJYYEPK.js.map → chunk-REJ5HLIM.js.map} +0 -0
- package/dist/{chunk-WVFGV5FT.js → chunk-WUFLGETN.js} +39 -2
- package/dist/{chunk-WVFGV5FT.js.map → chunk-WUFLGETN.js.map} +3 -3
- package/dist/core.js +0 -0
- package/dist/core.js.map +0 -0
- package/dist/editor.js +2 -2
- package/dist/editor.js.map +0 -0
- package/dist/flexdesk.css +30 -3
- package/dist/flow.js +3 -3
- package/dist/flow.js.map +0 -0
- package/dist/host.js +0 -0
- package/dist/host.js.map +0 -0
- package/dist/reset.css +0 -0
- package/dist/tile_registry-6WZPTUZV.js +0 -0
- package/dist/tile_registry-6WZPTUZV.js.map +0 -0
- package/dist/tiles.js +63 -20
- package/dist/tiles.js.map +2 -2
- package/dist/widgets.js +6 -6
- package/dist/widgets.js.map +0 -0
- package/dist/wm.js +5 -5
- package/dist/wm.js.map +0 -0
- package/docs/README.md +0 -0
- package/docs/best-practices.md +0 -0
- package/docs/components/charts.md +95 -0
- package/docs/components/command-palette.md +0 -0
- package/docs/components/conversation.md +0 -0
- package/docs/components/data-table-grid.md +0 -0
- package/docs/components/data-table.md +0 -0
- package/docs/components/editor.md +0 -0
- package/docs/components/flow-canvas-editor.md +0 -0
- package/docs/components/flow-editors.md +0 -0
- package/docs/components/flow-lane-editor.md +0 -0
- package/docs/components/flow-outline-editor.md +0 -0
- package/docs/components/forms-and-dialogs.md +0 -0
- package/docs/components/input-fields.md +0 -0
- package/docs/components/keymap.md +0 -0
- package/docs/components/markdown-and-outline.md +0 -0
- package/docs/components/menus.md +41 -0
- package/docs/components/notifications.md +0 -0
- package/docs/components/panels-and-desktops.md +0 -0
- package/docs/components/record-list-and-fact-table.md +0 -0
- package/docs/components/settings-view.md +0 -0
- package/docs/components/shell.md +0 -0
- package/docs/components/slide-out-panel.md +0 -0
- package/docs/components/tiles.md +25 -0
- package/docs/components/wizard.md +0 -0
- package/docs/concepts/building-and-packaging.md +0 -0
- package/docs/concepts/domain-neutrality.md +0 -0
- package/docs/concepts/host-port.md +0 -0
- package/docs/concepts/packages-and-entry-points.md +0 -0
- package/docs/concepts/peer-dependencies.md +0 -0
- package/docs/concepts/state-guard.md +0 -0
- package/docs/concepts/styling.md +0 -0
- package/docs/quickstart.md +0 -0
- package/editor.js +0 -0
- package/flow.js +0 -0
- package/host.js +0 -0
- package/package.json +1 -1
- package/src/canvas/canvas_adapter.js +0 -0
- package/src/canvas/edge_router.js +0 -0
- package/src/canvas/graph/connector_router.js +0 -0
- package/src/canvas/graph/history_service.js +0 -0
- package/src/canvas/graph/node_platform.js +0 -0
- package/src/canvas/index.js +0 -0
- package/src/canvas/layered_layout.js +0 -0
- package/src/charts/chart_types.js +3 -2
- package/src/charts/data_series_plot_window.js +0 -0
- package/src/charts/downsample.js +0 -0
- package/src/charts/plot_config.js +0 -0
- package/src/charts/plot_config_editor.js +8 -2
- package/src/charts/plot_grid.js +16 -4
- package/src/charts/plot_popout_window.js +2 -1
- package/src/charts/plotly_wrapper.js +0 -0
- package/src/charts/series_transforms.js +114 -20
- package/src/core/event_bus.js +0 -0
- package/src/core/logging.js +0 -0
- package/src/core/settings.js +0 -0
- package/src/core/state_guard.js +0 -0
- package/src/core/state_guard_config.js +0 -0
- package/src/core/state_machine.js +0 -0
- package/src/editor/editor_pane.js +0 -0
- package/src/editor/monaco_editor_factory.js +0 -0
- package/src/editor/monaco_loader.js +0 -0
- package/src/editor/notebook_search.js +0 -0
- package/src/editor/notebook_tab_bar.js +26 -7
- package/src/editor/notebook_undo_manager.js +0 -0
- package/src/editor/split_pane_container.js +0 -0
- package/src/flow/canvas_editor/connections.js +0 -0
- package/src/flow/canvas_editor/editor.js +0 -0
- package/src/flow/canvas_editor/index.js +0 -0
- package/src/flow/canvas_editor/layout.js +0 -0
- package/src/flow/canvas_editor/strings.js +0 -0
- package/src/flow/kit/always_before.js +0 -0
- package/src/flow/kit/catalogue.js +0 -0
- package/src/flow/kit/chip_input.js +0 -0
- package/src/flow/kit/dom.js +0 -0
- package/src/flow/kit/findings.js +0 -0
- package/src/flow/kit/history.js +0 -0
- package/src/flow/kit/index.js +0 -0
- package/src/flow/kit/keys.js +0 -0
- package/src/flow/kit/logic_graph.js +0 -0
- package/src/flow/kit/references.js +0 -0
- package/src/flow/kit/settings_panel.js +0 -0
- package/src/flow/kit/settings_schema.js +0 -0
- package/src/flow/kit/step_picker.js +0 -0
- package/src/flow/kit/strings.js +0 -0
- package/src/flow/kit/value_picker.js +0 -0
- package/src/flow/kit/widgets.js +0 -0
- package/src/flow/lanes/editor.js +0 -0
- package/src/flow/lanes/index.js +0 -0
- package/src/flow/lanes/layout.js +0 -0
- package/src/flow/lanes/pipeline.js +0 -0
- package/src/flow/lanes/preview.js +0 -0
- package/src/flow/lanes/strings.js +0 -0
- package/src/flow/outline/editor.js +0 -0
- package/src/flow/outline/index.js +0 -0
- package/src/flow/outline/mapping.js +0 -0
- package/src/flow/outline/menu.js +0 -0
- package/src/flow/outline/operations.js +0 -0
- package/src/flow/outline/recognise.js +0 -0
- package/src/flow/outline/strings.js +0 -0
- package/src/help/help_modal.js +0 -0
- package/src/help/help_registry.js +0 -0
- package/src/host/external_links.js +0 -0
- package/src/host/file_picker.js +0 -0
- package/src/host/host.js +0 -0
- package/src/host/photino_host.js +0 -0
- package/src/host/photino_host.md +0 -0
- package/src/host/pywebview_host.js +0 -0
- package/src/tiles/chart_tiles.js +0 -0
- package/src/tiles/config_schema.js +0 -0
- package/src/tiles/figure_tile.js +0 -0
- package/src/tiles/layout_persistence.js +0 -0
- package/src/tiles/list_tiles.js +0 -0
- package/src/tiles/scope_picker.js +0 -0
- package/src/tiles/tile_base.js +67 -16
- package/src/tiles/tile_config_form.js +0 -0
- package/src/tiles/tile_grid.js +0 -0
- package/src/tiles/tile_registry.js +0 -0
- package/src/tiling/bottom_panel_tabs.js +0 -0
- package/src/tiling/command_palette.js +0 -0
- package/src/tiling/content_registry.js +0 -0
- package/src/tiling/desktops.js +0 -0
- package/src/tiling/entity_sources.js +0 -0
- package/src/tiling/keymap.js +0 -0
- package/src/tiling/kind_taxonomy.js +0 -0
- package/src/tiling/landing_table.js +0 -0
- package/src/tiling/loading_overlay.js +0 -0
- package/src/tiling/nav_panel.js +0 -0
- package/src/tiling/page_factory.js +0 -0
- package/src/tiling/panel_availability.js +0 -0
- package/src/tiling/panel_keys.js +0 -0
- package/src/tiling/shell.js +0 -0
- package/src/tiling/tab_strip.js +0 -0
- package/src/tiling/tile_breadcrumb.js +0 -0
- package/src/tiling/tile_renderer.js +0 -0
- package/src/tiling/tile_tab_menu.js +0 -0
- package/src/tiling/tile_tree.js +0 -0
- package/src/tiling/wm.js +0 -0
- package/src/tiling/zoom.js +0 -0
- package/src/ui/base/component_base.js +0 -0
- package/src/ui/base/controller_base.js +0 -0
- package/src/ui/base/page_base.js +0 -0
- package/src/ui/components/about_dialog.js +0 -0
- package/src/ui/components/action_dropdown.js +19 -6
- package/src/ui/components/alert_log.js +0 -0
- package/src/ui/components/alerts_pane.js +0 -0
- package/src/ui/components/attribute_list_editor.js +0 -0
- package/src/ui/components/autocomplete_field.js +0 -0
- package/src/ui/components/cell_editor_host.js +0 -0
- package/src/ui/components/cell_editors.js +0 -0
- package/src/ui/components/cell_grid.js +0 -0
- package/src/ui/components/cell_paste.js +0 -0
- package/src/ui/components/cell_selection.js +0 -0
- package/src/ui/components/choice_controls.js +0 -0
- package/src/ui/components/color_field.js +0 -0
- package/src/ui/components/color_list_field.js +0 -0
- package/src/ui/components/column_fit.js +0 -0
- package/src/ui/components/column_groups.js +0 -0
- package/src/ui/components/column_order.js +0 -0
- package/src/ui/components/computing_status_window.js +0 -0
- package/src/ui/components/confirm_dialog.js +0 -0
- package/src/ui/components/context_menu.js +20 -20
- package/src/ui/components/conversation_view.js +0 -0
- package/src/ui/components/crosstab.js +0 -0
- package/src/ui/components/data_table.js +45 -19
- package/src/ui/components/detail_header.js +0 -0
- package/src/ui/components/document_outline.js +0 -0
- package/src/ui/components/drag_reorder.js +0 -0
- package/src/ui/components/fact_table.js +0 -0
- package/src/ui/components/fill_handle.js +0 -0
- package/src/ui/components/gallery_picker.js +0 -0
- package/src/ui/components/header_actions.js +0 -0
- package/src/ui/components/inline_renamer.js +0 -0
- package/src/ui/components/job_progress.js +0 -0
- package/src/ui/components/managed_window.js +0 -0
- package/src/ui/components/menu_bar.js +0 -0
- package/src/ui/components/modal.js +0 -0
- package/src/ui/components/notification_history.js +0 -0
- package/src/ui/components/progress.js +0 -0
- package/src/ui/components/record_list.js +0 -0
- package/src/ui/components/row_activation.js +0 -0
- package/src/ui/components/section_stack.js +0 -0
- package/src/ui/components/series.js +0 -0
- package/src/ui/components/settings_view.js +0 -0
- package/src/ui/components/slide_out_panel.js +0 -0
- package/src/ui/components/slider_field.js +0 -0
- package/src/ui/components/sortable_list.js +0 -0
- package/src/ui/components/staged_edits.js +0 -0
- package/src/ui/components/staged_history.js +0 -0
- package/src/ui/components/table_filter_chips.js +0 -0
- package/src/ui/components/table_state_store.js +0 -0
- package/src/ui/components/table_structure.js +0 -0
- package/src/ui/components/table_values.js +0 -0
- package/src/ui/components/tabs.js +0 -0
- package/src/ui/components/tag_input.js +0 -0
- package/src/ui/components/toast.js +0 -0
- package/src/ui/components/toggle_field.js +0 -0
- package/src/ui/components/tree_view.js +0 -0
- package/src/ui/components/tsv.js +0 -0
- package/src/ui/components/window_taskbar.js +0 -0
- package/src/ui/components/wizard.js +0 -0
- package/src/ui/controllers/window_chrome_controller.js +0 -0
- package/src/ui/notification_center.js +0 -0
- package/src/ui/utils/auto_scrollbars.js +0 -0
- package/src/ui/utils/markdown.js +0 -0
- package/src/ui/utils/menu_viewport.js +81 -0
- package/src/ui/utils/native_context_menu.js +0 -0
- package/src/ui/utils/overlay_scrollbar.js +0 -0
- package/src/ui/utils/raf_resize_observer.js +0 -0
- package/src/ui/utils/scroll_lock.js +0 -0
- package/src/ui/utils/strip_scroll.js +0 -0
- package/src/ui/utils/tooltip_service.js +0 -0
- package/tiles.js +0 -0
- package/widgets.js +0 -0
- package/wm.js +0 -0
- package/dist/chunk-LWV23YVE.js.map +0 -7
- package/dist/chunk-RMTRWWEO.js.map +0 -7
- package/dist/chunk-UURZ37SD.js.map +0 -7
- package/dist/chunk-UWO43BZU.js.map +0 -7
|
@@ -15,11 +15,44 @@
|
|
|
15
15
|
* },
|
|
16
16
|
* };
|
|
17
17
|
*
|
|
18
|
-
* `run(y, params)` resolves `{ [output]: number[] }`. It is called
|
|
19
|
-
* eligible trace (a 2-D line/scatter trace) for each transform with at
|
|
20
|
-
* output switched on, and every switched-on output it returns is
|
|
21
|
-
* extra trace in the source trace's colour, named
|
|
22
|
-
* the output's `lineStyle` (solid | dashed |
|
|
18
|
+
* `run(y, params, context)` resolves `{ [output]: number[] }`. It is called
|
|
19
|
+
* ONCE per eligible trace (a 2-D line/scatter trace) for each transform with at
|
|
20
|
+
* least one output switched on, and every switched-on output it returns is
|
|
21
|
+
* drawn as an extra trace in the source trace's colour, named
|
|
22
|
+
* `<source name><suffix>`, with the output's `lineStyle` (solid | dashed |
|
|
23
|
+
* dotted) and `lineWidth`.
|
|
24
|
+
*
|
|
25
|
+
* `y` is the drawn values (after the subplot's NaN handling and whatever the
|
|
26
|
+
* embedder's `resolveSeries` did, such as a rebase). `context` (0.17.8) says
|
|
27
|
+
* which series they are:
|
|
28
|
+
*
|
|
29
|
+
* { series, // the subplot's series entry the trace was drawn from
|
|
30
|
+
* // (its variable, scenario, ...); null when unknown
|
|
31
|
+
* subplot, // the subplot config
|
|
32
|
+
* results, // the results the figure was drawn from, or null
|
|
33
|
+
* resolveSeries } // the `(series, results, subplot) => { y, x? }` the
|
|
34
|
+
* // figure was drawn with, or null
|
|
35
|
+
*
|
|
36
|
+
* so a transform can look the same series up elsewhere (a baseline scenario)
|
|
37
|
+
* and resolve it the same way. renderPlotGrid (and so PlotPopoutWindow) runs
|
|
38
|
+
* transforms on the same traces as before 0.17.8 (overlays included, derived
|
|
39
|
+
* traces never); a trace drawn from one of the subplot's series gets that
|
|
40
|
+
* series, any other (an overlay) gets `series: null`. A transform written as
|
|
41
|
+
* `run(y, params)` ignores the third argument and works as before.
|
|
42
|
+
*
|
|
43
|
+
* A parameter is a number field by default:
|
|
44
|
+
*
|
|
45
|
+
* window: { label: 'Window', default: 5, min: 1, step: 1 }
|
|
46
|
+
*
|
|
47
|
+
* or, declared `type: 'choice'` (0.17.8), a select over `options`: an array of
|
|
48
|
+
* `{ value, label }`, or a function `(subplot) => [{ value, label }]` called
|
|
49
|
+
* when the controls are drawn (and when the parameter needs its default):
|
|
50
|
+
*
|
|
51
|
+
* baseline: { label: 'Compare with', type: 'choice',
|
|
52
|
+
* options: () => scenarios.map((s) => ({ value: s.id, label: s.name })) }
|
|
53
|
+
*
|
|
54
|
+
* The chosen value is saved and passed to `run` like a number. Without a
|
|
55
|
+
* `default` and with nothing saved, a choice is its first enabled option.
|
|
23
56
|
*
|
|
24
57
|
* What is switched on lives in the subplot, under `subplot.transforms`:
|
|
25
58
|
*
|
|
@@ -30,14 +63,38 @@
|
|
|
30
63
|
*/
|
|
31
64
|
|
|
32
65
|
import { buildTrace } from './chart_types.js';
|
|
66
|
+
import { flatChoices, selectBox } from '../ui/components/choice_controls.js';
|
|
67
|
+
|
|
68
|
+
/** Whether a parameter spec is a choice (a select) rather than a number. */
|
|
69
|
+
const isChoice = (spec) => spec?.type === 'choice';
|
|
70
|
+
|
|
71
|
+
/** A choice parameter's options for `subplot`: its array, or what its function returns. */
|
|
72
|
+
function choiceOptions(spec, subplot) {
|
|
73
|
+
const options = typeof spec.options === 'function' ? spec.options(subplot) : spec.options;
|
|
74
|
+
return Array.isArray(options) ? options : [];
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
/**
|
|
78
|
+
* A choice parameter's value when none is declared or saved: the option
|
|
79
|
+
* selectBox selects for it, its first enabled one, `{ group, options }`
|
|
80
|
+
* entries flattened in order (the first of all when every one is disabled).
|
|
81
|
+
*/
|
|
82
|
+
function firstChoice(spec, subplot) {
|
|
83
|
+
const flat = flatChoices(choiceOptions(spec, subplot));
|
|
84
|
+
return (flat.find((o) => !o.disabled) ?? flat[0])?.value;
|
|
85
|
+
}
|
|
33
86
|
|
|
34
87
|
/** A transform's parameter values: its declared defaults under the subplot's own. */
|
|
35
|
-
function resolveParams(transform, state) {
|
|
88
|
+
function resolveParams(transform, state, subplot) {
|
|
89
|
+
const saved = state?.params ?? {};
|
|
36
90
|
const params = {};
|
|
37
91
|
for (const [name, spec] of Object.entries(transform.params ?? {})) {
|
|
38
92
|
params[name] = spec?.default;
|
|
93
|
+
if (isChoice(spec) && spec.default === undefined && saved[name] === undefined) {
|
|
94
|
+
params[name] = firstChoice(spec, subplot);
|
|
95
|
+
}
|
|
39
96
|
}
|
|
40
|
-
return { ...params, ...
|
|
97
|
+
return { ...params, ...saved };
|
|
41
98
|
}
|
|
42
99
|
|
|
43
100
|
/** The output names of `transform` that `state` switches on, in declared order. */
|
|
@@ -60,23 +117,34 @@ function isEligible(trace) {
|
|
|
60
117
|
* @param {Object} [options]
|
|
61
118
|
* @param {Function} [options.onError] - `({ transformId, traceName, error })`,
|
|
62
119
|
* called for each skipped run.
|
|
120
|
+
* @param {Function} [options.seriesOf] - `(trace) => series | null`: the series
|
|
121
|
+
* config a trace was drawn from, passed as `context.series` (null for a
|
|
122
|
+
* trace it names none for, and for every trace without it). It does not
|
|
123
|
+
* choose the sources: every eligible trace is run on, as before.
|
|
124
|
+
* @param {Object} [options.results] - The results the figure was drawn from
|
|
125
|
+
* (`context.results`).
|
|
126
|
+
* @param {Function} [options.resolveSeries] - The resolver the figure was drawn
|
|
127
|
+
* with (`context.resolveSeries`).
|
|
63
128
|
* @returns {Promise<Object[]>} The extra traces, in transform then trace order.
|
|
64
129
|
*/
|
|
65
|
-
async function deriveSeriesTraces(traces, subplot, seriesTransforms,
|
|
130
|
+
async function deriveSeriesTraces(traces, subplot, seriesTransforms,
|
|
131
|
+
{ onError, seriesOf, results, resolveSeries } = {}) {
|
|
66
132
|
const derived = [];
|
|
67
133
|
if (!seriesTransforms) return derived;
|
|
68
|
-
const sources = traces.filter(isEligible)
|
|
134
|
+
const sources = traces.filter(isEligible)
|
|
135
|
+
.map((trace) => ({ trace, series: typeof seriesOf === 'function' ? (seriesOf(trace) ?? null) : null }));
|
|
69
136
|
|
|
70
137
|
for (const [transformId, transform] of Object.entries(seriesTransforms)) {
|
|
71
138
|
const state = subplot?.transforms?.[transformId];
|
|
72
139
|
const outputs = enabledOutputs(transform, state);
|
|
73
140
|
if (!outputs.length || typeof transform?.run !== 'function') continue;
|
|
74
|
-
const params = resolveParams(transform, state);
|
|
141
|
+
const params = resolveParams(transform, state, subplot);
|
|
75
142
|
|
|
76
|
-
for (const source of sources) {
|
|
143
|
+
for (const { trace: source, series } of sources) {
|
|
144
|
+
const context = { series, subplot, results: results ?? null, resolveSeries: resolveSeries ?? null };
|
|
77
145
|
let result;
|
|
78
146
|
try {
|
|
79
|
-
result = await transform.run(source.y, params);
|
|
147
|
+
result = await transform.run(source.y, params, context);
|
|
80
148
|
} catch (error) {
|
|
81
149
|
onError?.({ transformId, traceName: source.name, error });
|
|
82
150
|
continue;
|
|
@@ -112,7 +180,8 @@ async function deriveSeriesTraces(traces, subplot, seriesTransforms, { onError }
|
|
|
112
180
|
|
|
113
181
|
/**
|
|
114
182
|
* The controls for `seriesTransforms` in a subplot's config: per transform, a
|
|
115
|
-
* toggle for each output and a number field for
|
|
183
|
+
* toggle for each output and, for each parameter, a number field or, for a
|
|
184
|
+
* `type: 'choice'` parameter, a select (choice_controls' selectBox). They edit
|
|
116
185
|
* `subplot.transforms` in place and call `onChange()` after every edit. With no
|
|
117
186
|
* transforms (null or `{}`) nothing is rendered.
|
|
118
187
|
*
|
|
@@ -173,22 +242,47 @@ function renderSeriesTransformControls(container, subplot, seriesTransforms, { o
|
|
|
173
242
|
row.className = 'twm-series-transforms__row';
|
|
174
243
|
const text = document.createElement('span');
|
|
175
244
|
text.textContent = spec?.label ?? name;
|
|
245
|
+
const writeParam = (value) => {
|
|
246
|
+
const state = stateOf(transformId);
|
|
247
|
+
const params = { ...(state.params ?? {}) };
|
|
248
|
+
if (value === undefined) delete params[name];
|
|
249
|
+
else params[name] = value;
|
|
250
|
+
state.params = params;
|
|
251
|
+
onChange?.();
|
|
252
|
+
};
|
|
253
|
+
const saved = subplot.transforms?.[transformId]?.params?.[name];
|
|
254
|
+
|
|
255
|
+
if (isChoice(spec)) {
|
|
256
|
+
const current = saved ?? spec.default ?? firstChoice(spec, subplot);
|
|
257
|
+
const choice = selectBox(choiceOptions(spec, subplot), current, {
|
|
258
|
+
label: spec?.label ?? name,
|
|
259
|
+
valueAttr: 'value',
|
|
260
|
+
className: 'twm-series-transforms__param twm-series-transforms__select',
|
|
261
|
+
});
|
|
262
|
+
choice.box.addEventListener('change', () => {
|
|
263
|
+
const value = choice.valueOf();
|
|
264
|
+
// Redrawn with the chosen value, as settings do: a stale
|
|
265
|
+
// '(not found)' entry goes once an offered option is picked.
|
|
266
|
+
choice.setOptions(choiceOptions(spec, subplot), value);
|
|
267
|
+
writeParam(value);
|
|
268
|
+
});
|
|
269
|
+
paramInputs.push(choice.box);
|
|
270
|
+
row.append(text, choice.box);
|
|
271
|
+
group.appendChild(row);
|
|
272
|
+
continue;
|
|
273
|
+
}
|
|
274
|
+
|
|
176
275
|
const input = document.createElement('input');
|
|
177
276
|
input.type = 'number';
|
|
178
277
|
input.className = 'twm-series-transforms__param';
|
|
179
278
|
for (const attr of ['min', 'max', 'step']) {
|
|
180
279
|
if (spec?.[attr] != null) input[attr] = String(spec[attr]);
|
|
181
280
|
}
|
|
182
|
-
const current =
|
|
281
|
+
const current = saved ?? spec?.default;
|
|
183
282
|
input.value = current == null ? '' : String(current);
|
|
184
283
|
input.addEventListener('change', () => {
|
|
185
284
|
const value = parseFloat(input.value);
|
|
186
|
-
|
|
187
|
-
const params = { ...(state.params ?? {}) };
|
|
188
|
-
if (Number.isFinite(value)) params[name] = value;
|
|
189
|
-
else delete params[name];
|
|
190
|
-
state.params = params;
|
|
191
|
-
onChange?.();
|
|
285
|
+
writeParam(Number.isFinite(value) ? value : undefined);
|
|
192
286
|
});
|
|
193
287
|
paramInputs.push(input);
|
|
194
288
|
row.append(text, input);
|
package/src/core/event_bus.js
CHANGED
|
File without changes
|
package/src/core/logging.js
CHANGED
|
File without changes
|
package/src/core/settings.js
CHANGED
|
File without changes
|
package/src/core/state_guard.js
CHANGED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
@@ -24,6 +24,7 @@
|
|
|
24
24
|
|
|
25
25
|
import { DragReorder } from '../ui/components/drag_reorder.js';
|
|
26
26
|
import { revealInStrip, wheelStripSideways } from '../ui/utils/strip_scroll.js';
|
|
27
|
+
import { placeMenuInViewport, moveMenuFocus, focusMenuItem } from '../ui/utils/menu_viewport.js';
|
|
27
28
|
|
|
28
29
|
/** The MIME type a dragged editor tab carries when the embedder names none. */
|
|
29
30
|
export const DEFAULT_TAB_DRAG_MIME = 'application/x-flexdesk-tab';
|
|
@@ -64,6 +65,8 @@ export class NotebookTabBar {
|
|
|
64
65
|
|
|
65
66
|
/** @type {HTMLElement|null} */
|
|
66
67
|
#contextMenuEl = null;
|
|
68
|
+
/** BUG-0040. What had focus when the menu opened. @type {Element|null} */
|
|
69
|
+
#contextMenuReturnFocus = null;
|
|
67
70
|
|
|
68
71
|
/** @type {Function|null} */
|
|
69
72
|
#boundHideContextMenu = null;
|
|
@@ -417,6 +420,7 @@ export class NotebookTabBar {
|
|
|
417
420
|
|
|
418
421
|
const menu = document.createElement('div');
|
|
419
422
|
menu.className = 'nb-context-menu';
|
|
423
|
+
menu.setAttribute('role', 'menu');
|
|
420
424
|
|
|
421
425
|
for (const item of cleaned) {
|
|
422
426
|
if (item.separator) {
|
|
@@ -427,6 +431,8 @@ export class NotebookTabBar {
|
|
|
427
431
|
}
|
|
428
432
|
|
|
429
433
|
const btn = document.createElement('button');
|
|
434
|
+
btn.type = 'button';
|
|
435
|
+
btn.setAttribute('role', 'menuitem');
|
|
430
436
|
btn.className = 'nb-context-menu__item';
|
|
431
437
|
if (item.danger) btn.classList.add('nb-context-menu__item--danger');
|
|
432
438
|
if (item.disabled) btn.classList.add('nb-context-menu__item--disabled');
|
|
@@ -445,15 +451,14 @@ export class NotebookTabBar {
|
|
|
445
451
|
menu.appendChild(btn);
|
|
446
452
|
}
|
|
447
453
|
|
|
454
|
+
this.#contextMenuReturnFocus = document.activeElement;
|
|
448
455
|
document.body.appendChild(menu);
|
|
449
456
|
this.#contextMenuEl = menu;
|
|
450
457
|
|
|
451
|
-
//
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
menu.style.left = `${Math.max(0, left)}px`;
|
|
456
|
-
menu.style.top = `${Math.max(0, top)}px`;
|
|
458
|
+
// BUG-0040. Inside the window, at most its height, scrolling when
|
|
459
|
+
// longer; the keyboard starts on the first item it can use.
|
|
460
|
+
placeMenuInViewport(menu, x, y);
|
|
461
|
+
focusMenuItem(this.#contextMenuItems()[0]);
|
|
457
462
|
|
|
458
463
|
// Animate in
|
|
459
464
|
requestAnimationFrame(() => menu.classList.add('visible'));
|
|
@@ -468,15 +473,29 @@ export class NotebookTabBar {
|
|
|
468
473
|
|
|
469
474
|
#hideContextMenu() {
|
|
470
475
|
if (!this.#contextMenuEl) return;
|
|
476
|
+
const returnTo = this.#contextMenuReturnFocus;
|
|
477
|
+
const held = this.#contextMenuEl.contains(document.activeElement);
|
|
471
478
|
this.#contextMenuEl.remove();
|
|
472
479
|
this.#contextMenuEl = null;
|
|
480
|
+
this.#contextMenuReturnFocus = null;
|
|
473
481
|
document.removeEventListener('click', this.#boundHideContextMenu, true);
|
|
474
482
|
document.removeEventListener('contextmenu', this.#boundHideContextMenu, true);
|
|
475
483
|
document.removeEventListener('keydown', this.#onKeyDown);
|
|
484
|
+
if (held && returnTo?.isConnected) returnTo.focus?.({ preventScroll: true });
|
|
485
|
+
}
|
|
486
|
+
|
|
487
|
+
/** BUG-0040. The menu's items the keyboard can land on. */
|
|
488
|
+
#contextMenuItems() {
|
|
489
|
+
return this.#contextMenuEl
|
|
490
|
+
? [...this.#contextMenuEl.querySelectorAll('.nb-context-menu__item:not(.nb-context-menu__item--disabled)')]
|
|
491
|
+
: [];
|
|
476
492
|
}
|
|
477
493
|
|
|
478
494
|
#onKeyDown = (e) => {
|
|
479
|
-
if (e.key === 'Escape') this.#hideContextMenu();
|
|
495
|
+
if (e.key === 'Escape') { this.#hideContextMenu(); return; }
|
|
496
|
+
// BUG-0040. Up/Down/Home/End move between the items and scroll the
|
|
497
|
+
// focused one into view; Enter and Space are the buttons' own.
|
|
498
|
+
moveMenuFocus(e, this.#contextMenuItems());
|
|
480
499
|
};
|
|
481
500
|
|
|
482
501
|
#handleContextMenuAction(action, filePath) {
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
package/src/flow/kit/dom.js
CHANGED
|
File without changes
|
package/src/flow/kit/findings.js
CHANGED
|
File without changes
|
package/src/flow/kit/history.js
CHANGED
|
File without changes
|
package/src/flow/kit/index.js
CHANGED
|
File without changes
|
package/src/flow/kit/keys.js
CHANGED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
package/src/flow/kit/strings.js
CHANGED
|
File without changes
|
|
File without changes
|
package/src/flow/kit/widgets.js
CHANGED
|
File without changes
|
package/src/flow/lanes/editor.js
CHANGED
|
File without changes
|
package/src/flow/lanes/index.js
CHANGED
|
File without changes
|
package/src/flow/lanes/layout.js
CHANGED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
package/src/flow/outline/menu.js
CHANGED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
package/src/help/help_modal.js
CHANGED
|
File without changes
|
|
File without changes
|
|
File without changes
|
package/src/host/file_picker.js
CHANGED
|
File without changes
|
package/src/host/host.js
CHANGED
|
File without changes
|
package/src/host/photino_host.js
CHANGED
|
File without changes
|
package/src/host/photino_host.md
CHANGED
|
File without changes
|
|
File without changes
|
package/src/tiles/chart_tiles.js
CHANGED
|
File without changes
|
|
File without changes
|
package/src/tiles/figure_tile.js
CHANGED
|
File without changes
|
|
File without changes
|
package/src/tiles/list_tiles.js
CHANGED
|
File without changes
|
|
File without changes
|
package/src/tiles/tile_base.js
CHANGED
|
@@ -8,6 +8,8 @@
|
|
|
8
8
|
|
|
9
9
|
import { openRawTracesWindow } from '../charts/plot_popout_window.js';
|
|
10
10
|
import { formatVariableLabel } from './config_schema.js';
|
|
11
|
+
import { ActionDropdown } from '../ui/components/action_dropdown.js';
|
|
12
|
+
import { modalHost } from '../ui/components/modal.js';
|
|
11
13
|
// The host is INJECTED, not fetched from a global.
|
|
12
14
|
//
|
|
13
15
|
// This imported `appHost()` from ui/js/ecoagent/app_host.js — a tile reaching into
|
|
@@ -403,6 +405,12 @@ export class TileBase {
|
|
|
403
405
|
if (this._disposed) return;
|
|
404
406
|
this._disposed = true;
|
|
405
407
|
|
|
408
|
+
// An open ⋯ menu lives on document.body; take it back first.
|
|
409
|
+
this._closeTileMenu();
|
|
410
|
+
this._menuButton = null;
|
|
411
|
+
this._menuDropdown = null;
|
|
412
|
+
this._menuHome = null;
|
|
413
|
+
|
|
406
414
|
// Close expand window if open
|
|
407
415
|
if (this._expandWindow?.isVisible) {
|
|
408
416
|
this._expandWindow.close();
|
|
@@ -485,6 +493,13 @@ export class TileBase {
|
|
|
485
493
|
* @private
|
|
486
494
|
*/
|
|
487
495
|
_buildChrome() {
|
|
496
|
+
// A rebuilt header gets a new ⋯ menu; an open old one must not stay
|
|
497
|
+
// behind on document.body.
|
|
498
|
+
this._closeTileMenu();
|
|
499
|
+
this._menuButton = null;
|
|
500
|
+
this._menuDropdown = null;
|
|
501
|
+
this._menuHome = null;
|
|
502
|
+
|
|
488
503
|
// Header with drag handle and controls
|
|
489
504
|
const header = document.createElement('div');
|
|
490
505
|
header.className = 'tile-header';
|
|
@@ -584,23 +599,13 @@ export class TileBase {
|
|
|
584
599
|
const menuBtn = header.querySelector('.tile-menu-btn');
|
|
585
600
|
const menuDropdown = header.querySelector('.tile-menu-dropdown');
|
|
586
601
|
if (menuBtn && menuDropdown) {
|
|
602
|
+
this._menuButton = menuBtn;
|
|
603
|
+
this._menuDropdown = menuDropdown;
|
|
604
|
+
this._menuHome = menuDropdown.parentNode;
|
|
587
605
|
menuBtn.addEventListener('click', (e) => {
|
|
588
606
|
e.stopPropagation();
|
|
589
|
-
|
|
590
|
-
|
|
591
|
-
if (!isOpen) {
|
|
592
|
-
// Close on outside click
|
|
593
|
-
const closeMenu = (ev) => {
|
|
594
|
-
if (!menuDropdown.contains(ev.target) && ev.target !== menuBtn) {
|
|
595
|
-
menuDropdown.hidden = true;
|
|
596
|
-
document.removeEventListener('pointerdown', closeMenu, true);
|
|
597
|
-
}
|
|
598
|
-
};
|
|
599
|
-
// Delay to avoid immediate close from the same click
|
|
600
|
-
requestAnimationFrame(() => {
|
|
601
|
-
document.addEventListener('pointerdown', closeMenu, true);
|
|
602
|
-
});
|
|
603
|
-
}
|
|
607
|
+
if (menuDropdown.hidden) this._openTileMenu();
|
|
608
|
+
else this._closeTileMenu();
|
|
604
609
|
});
|
|
605
610
|
// One listener per rendered entry, dispatching by `data-action`
|
|
606
611
|
// into `_onMenuAction`. Wiring each action by name here is what
|
|
@@ -609,7 +614,7 @@ export class TileBase {
|
|
|
609
614
|
menuDropdown.querySelectorAll('.tile-menu-item').forEach((itemEl) => {
|
|
610
615
|
itemEl.addEventListener('click', (e) => {
|
|
611
616
|
e.stopPropagation();
|
|
612
|
-
|
|
617
|
+
this._closeTileMenu();
|
|
613
618
|
this._onMenuAction(itemEl.dataset.action);
|
|
614
619
|
});
|
|
615
620
|
});
|
|
@@ -654,6 +659,52 @@ export class TileBase {
|
|
|
654
659
|
}
|
|
655
660
|
}
|
|
656
661
|
|
|
662
|
+
/**
|
|
663
|
+
* Open the ⋯ menu. It is drawn on `document.body` (or the open modal's
|
|
664
|
+
* host, as `showContextMenu` is), not inside the tile: a tile clips its
|
|
665
|
+
* content, so a menu wider than a narrow tile lost its left part. It is
|
|
666
|
+
* placed with `ActionDropdown.position` — fixed, under the button (above
|
|
667
|
+
* when there is no room), right edges aligned, kept inside the window.
|
|
668
|
+
* @private
|
|
669
|
+
*/
|
|
670
|
+
_openTileMenu() {
|
|
671
|
+
const btn = this._menuButton;
|
|
672
|
+
const menu = this._menuDropdown;
|
|
673
|
+
if (!btn || !menu || !menu.hidden) return;
|
|
674
|
+
(modalHost() || document.body).appendChild(menu);
|
|
675
|
+
menu.hidden = false;
|
|
676
|
+
ActionDropdown.position(btn, menu, { align: 'end' });
|
|
677
|
+
// Close on a press outside the menu and its button. Added a frame
|
|
678
|
+
// later so the press that opened it does not close it.
|
|
679
|
+
this._menuOutsideListener = (ev) => {
|
|
680
|
+
if (!menu.contains(ev.target) && !btn.contains(ev.target)) this._closeTileMenu();
|
|
681
|
+
};
|
|
682
|
+
const listener = this._menuOutsideListener;
|
|
683
|
+
requestAnimationFrame(() => {
|
|
684
|
+
if (this._menuOutsideListener === listener) {
|
|
685
|
+
document.addEventListener('pointerdown', listener, true);
|
|
686
|
+
}
|
|
687
|
+
});
|
|
688
|
+
}
|
|
689
|
+
|
|
690
|
+
/**
|
|
691
|
+
* Close the ⋯ menu and put it back in the tile's header.
|
|
692
|
+
* @private
|
|
693
|
+
*/
|
|
694
|
+
_closeTileMenu() {
|
|
695
|
+
const menu = this._menuDropdown;
|
|
696
|
+
if (this._menuOutsideListener) {
|
|
697
|
+
document.removeEventListener('pointerdown', this._menuOutsideListener, true);
|
|
698
|
+
this._menuOutsideListener = null;
|
|
699
|
+
}
|
|
700
|
+
if (!menu) return;
|
|
701
|
+
menu.hidden = true;
|
|
702
|
+
for (const prop of ['position', 'top', 'bottom', 'left', 'right', 'maxHeight', 'overflowY']) {
|
|
703
|
+
menu.style[prop] = '';
|
|
704
|
+
}
|
|
705
|
+
if (this._menuHome && menu.parentNode !== this._menuHome) this._menuHome.appendChild(menu);
|
|
706
|
+
}
|
|
707
|
+
|
|
657
708
|
/**
|
|
658
709
|
* Handle config button click — highlight tile and emit config request.
|
|
659
710
|
* @private
|
|
File without changes
|
package/src/tiles/tile_grid.js
CHANGED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
package/src/tiling/desktops.js
CHANGED
|
File without changes
|
|
File without changes
|
package/src/tiling/keymap.js
CHANGED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
package/src/tiling/nav_panel.js
CHANGED
|
File without changes
|
|
File without changes
|
|
File without changes
|
package/src/tiling/panel_keys.js
CHANGED
|
File without changes
|
package/src/tiling/shell.js
CHANGED
|
File without changes
|
package/src/tiling/tab_strip.js
CHANGED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
package/src/tiling/tile_tree.js
CHANGED
|
File without changes
|
package/src/tiling/wm.js
CHANGED
|
File without changes
|
package/src/tiling/zoom.js
CHANGED
|
File without changes
|
|
File without changes
|
|
File without changes
|
package/src/ui/base/page_base.js
CHANGED
|
File without changes
|
|
File without changes
|