flexdesk 0.17.16 → 0.17.18
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/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 +32 -1
- package/css/flexdesk.css +32 -1
- package/css/reset.css +0 -0
- package/css/tokens.css +3 -0
- package/dist/canvas.js +0 -0
- package/dist/canvas.js.map +0 -0
- package/dist/chunk-3PHCPZHT.js +0 -0
- package/dist/chunk-3PHCPZHT.js.map +0 -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-JKZLNKG6.js → chunk-HKPB6OFA.js} +90 -25
- package/dist/{chunk-JKZLNKG6.js.map → chunk-HKPB6OFA.js.map} +2 -2
- package/dist/chunk-HNU6MM2B.js +0 -0
- package/dist/chunk-HNU6MM2B.js.map +0 -0
- package/dist/chunk-JYWURG5T.js +0 -0
- package/dist/chunk-JYWURG5T.js.map +0 -0
- package/dist/chunk-N7HC3ADV.js +0 -0
- package/dist/chunk-N7HC3ADV.js.map +0 -0
- package/dist/editor.js.map +0 -0
- package/dist/flexdesk.css +32 -1
- 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/tokens.css +3 -0
- package/dist/widgets.js +4115 -4089
- package/dist/widgets.js.map +4 -4
- package/dist/wm.js +115 -31
- package/dist/wm.js.map +2 -2
- 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/input-fields.md +0 -0
- package/docs/components/markdown-and-outline.md +0 -0
- package/docs/components/menus.md +38 -1
- package/docs/components/notifications.md +23 -1
- package/docs/components/panels-and-desktops.md +22 -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 +54 -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/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/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/plotly_wrapper.js +0 -0
- 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_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_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_config_form.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/entity_sources.js +0 -0
- package/src/tiling/kind_taxonomy.js +21 -13
- 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 +4 -1
- package/src/tiling/tab_strip.js +0 -0
- package/src/tiling/tile_renderer.js +0 -0
- package/src/tiling/tile_tab_menu.js +0 -0
- package/src/tiling/wm.js +123 -28
- 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/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/conversation_view.js +0 -0
- package/src/ui/components/crosstab.js +0 -0
- 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/menu_bar.js +101 -24
- package/src/ui/components/notification_history.js +11 -1
- 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/tsv.js +0 -0
- package/src/ui/components/window_taskbar.js +0 -0
- package/src/ui/controllers/window_chrome_controller.js +4 -1
- package/src/ui/notification_center.js +47 -1
- package/src/ui/utils/auto_scrollbars.js +0 -0
- package/src/ui/utils/markdown.js +0 -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/wm.js +0 -0
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,41 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## 0.17.18 (2026-10-27)
|
|
4
|
+
|
|
5
|
+
A patch release. One additive menu bar option; one entry changes what
|
|
6
|
+
embedders see (listed under "Changed behaviour").
|
|
7
|
+
|
|
8
|
+
### Added
|
|
9
|
+
|
|
10
|
+
- [A hamburger instead of the bar: `style: 'hamburger'`](docs/components/menus.md#a-hamburger-instead-of-the-bar-style-hamburger-01718): `createMenuBar` (and `createShell`'s `menuBar`) can draw the menus as one icon button whose menu flies out each menu's items. Same model, `onAction`, `setEnabled` / `setChecked` and `commands()`; `open(menuId)` opens it with that menu flown out. `bar.setStyle('bar' | 'hamburger')` switches at run time and `bar.style` reads it; `icon` sets the glyph (`'menu'`) (STORY-0133).
|
|
11
|
+
|
|
12
|
+
### Changed behaviour
|
|
13
|
+
|
|
14
|
+
- `WindowChromeController` never starts a window drag from a press inside a `.twm-menubar`: a hamburger in the top bar drops its menus inside the bar, and a press on a menu's padding or separator dragged the window (STORY-0133).
|
|
15
|
+
|
|
16
|
+
### Removed or renamed exports
|
|
17
|
+
|
|
18
|
+
None. New: `MenuBar#setStyle`, `MenuBar#style`, the `style` and `icon` options, the `.twm-menubar--hamburger` and `.twm-menubar__title--icon` classes.
|
|
19
|
+
|
|
20
|
+
## 0.17.17 (2026-10-27)
|
|
21
|
+
|
|
22
|
+
A patch release. One additive taxonomy option and notification copying; one
|
|
23
|
+
entry changes what embedders see (listed under "Changed behaviour").
|
|
24
|
+
|
|
25
|
+
### Added
|
|
26
|
+
|
|
27
|
+
- [A kind that exists once per desktop: `single: 'desktop'`](docs/components/shell.md#a-kind-that-exists-once-per-desktop-single-desktop-01717): at most one instance per virtual desktop. The top nav, `navigate`, `openInPrimary` and the other open paths reveal the active desktop's instance or open one there, and never switch desktop; navigating inside a window looks on the window's own desktop; the move verbs refuse to carry the kind onto a desktop that holds it (`wm.desktopMoveRefusal`, greyed menu rows); a restored layout and page restores dedupe per desktop. `single: true` is unchanged. New: `taxonomy.isSinglePerDesktop(kind)` (STORY-0130).
|
|
28
|
+
- [Copy message](docs/components/notifications.md#copy-message): right-clicking a toast or a `NotificationHistory` entry opens the context menu with **Copy message** (title, message and description as plain text); notification text is selectable, and a click on a toast's text selects it instead of closing the toast (STORY-0131).
|
|
29
|
+
|
|
30
|
+
### Changed behaviour
|
|
31
|
+
|
|
32
|
+
- Every `showContextMenu` menu draws on the new `--z-context-menu` layer (10100, tokens.css), over toasts and managed windows; it was `z-index: 5000` (STORY-0131).
|
|
33
|
+
- A click on a toast's text (title, message, description, status) no longer closes it; a click on the card outside its text, or ×, does (STORY-0131).
|
|
34
|
+
|
|
35
|
+
### Removed or renamed exports
|
|
36
|
+
|
|
37
|
+
None. New: `isSinglePerDesktop` on the taxonomy, `wm.desktopMoveRefusal`, `notificationText` (notification_center.js), the `--z-context-menu` custom property.
|
|
38
|
+
|
|
3
39
|
## 0.17.16 (2026-10-27)
|
|
4
40
|
|
|
5
41
|
A patch release. Two new widgets and options; the other entries change what
|
package/LICENSE
CHANGED
|
File without changes
|
package/README.md
CHANGED
|
File without changes
|
package/THIRD_PARTY_LICENSES.md
CHANGED
|
File without changes
|
package/canvas.js
CHANGED
|
File without changes
|
package/charts.js
CHANGED
|
File without changes
|
package/core.js
CHANGED
|
File without changes
|
package/css/base.css
CHANGED
|
@@ -521,6 +521,17 @@
|
|
|
521
521
|
color: #bcbcbc;
|
|
522
522
|
line-height: 1.4;
|
|
523
523
|
}
|
|
524
|
+
/* The text of a toast and of a history entry can be selected and copied (STORY-0131);
|
|
525
|
+
* the body's `user-select: none` (reset.css) would otherwise hold it. */
|
|
526
|
+
.twm-notification__title,
|
|
527
|
+
.twm-notification__body,
|
|
528
|
+
.twm-notification__description,
|
|
529
|
+
.twm-notification__status,
|
|
530
|
+
.twm-notification-history__item-title,
|
|
531
|
+
.twm-notification-history__item-body {
|
|
532
|
+
user-select: text;
|
|
533
|
+
cursor: text;
|
|
534
|
+
}
|
|
524
535
|
.twm-notification-history__empty {
|
|
525
536
|
text-align: center;
|
|
526
537
|
color: #6c6c6c;
|
|
@@ -1849,7 +1860,7 @@ body.twm-dt-col-resizing {
|
|
|
1849
1860
|
border: 1px solid var(--surface-3);
|
|
1850
1861
|
border-radius: var(--radius-md);
|
|
1851
1862
|
box-shadow: 0 6px 24px rgba(0,0,0,0.45);
|
|
1852
|
-
z-index:
|
|
1863
|
+
z-index: var(--z-context-menu);
|
|
1853
1864
|
display: none;
|
|
1854
1865
|
pointer-events: auto;
|
|
1855
1866
|
min-width: 180px;
|
|
@@ -7022,6 +7033,26 @@ button.twm-about-dialog__btn--close:focus {
|
|
|
7022
7033
|
margin: var(--space-xs) var(--space-md);
|
|
7023
7034
|
background: var(--surface-3);
|
|
7024
7035
|
}
|
|
7036
|
+
/* The hamburger (STORY-0133, `style: 'hamburger'`): one icon button in place
|
|
7037
|
+
* of the titles, the size of the top bar's other icon buttons
|
|
7038
|
+
* (.twm-panel-toggle-btn: a 22px box, an --font-size-xl glyph). Its menu
|
|
7039
|
+
* lists the menus, each flying out its items. */
|
|
7040
|
+
.twm-menubar--hamburger {
|
|
7041
|
+
align-items: center;
|
|
7042
|
+
}
|
|
7043
|
+
.twm-menubar__title--icon {
|
|
7044
|
+
display: inline-flex;
|
|
7045
|
+
align-items: center;
|
|
7046
|
+
justify-content: center;
|
|
7047
|
+
width: 22px;
|
|
7048
|
+
height: 22px;
|
|
7049
|
+
padding: 0;
|
|
7050
|
+
color: var(--text-secondary);
|
|
7051
|
+
}
|
|
7052
|
+
.twm-menubar__title--icon .material-symbols-outlined {
|
|
7053
|
+
font-size: var(--font-size-xl);
|
|
7054
|
+
line-height: 1;
|
|
7055
|
+
}
|
|
7025
7056
|
/* ══ end MENU BAR ══ */
|
|
7026
7057
|
|
|
7027
7058
|
/* ══ TOGGLE ══════════════════════════════════════════════════════════
|
package/css/flexdesk.css
CHANGED
|
@@ -551,6 +551,17 @@
|
|
|
551
551
|
color: #bcbcbc;
|
|
552
552
|
line-height: 1.4;
|
|
553
553
|
}
|
|
554
|
+
/* The text of a toast and of a history entry can be selected and copied (STORY-0131);
|
|
555
|
+
* the body's `user-select: none` (reset.css) would otherwise hold it. */
|
|
556
|
+
.twm-notification__title,
|
|
557
|
+
.twm-notification__body,
|
|
558
|
+
.twm-notification__description,
|
|
559
|
+
.twm-notification__status,
|
|
560
|
+
.twm-notification-history__item-title,
|
|
561
|
+
.twm-notification-history__item-body {
|
|
562
|
+
user-select: text;
|
|
563
|
+
cursor: text;
|
|
564
|
+
}
|
|
554
565
|
.twm-notification-history__empty {
|
|
555
566
|
text-align: center;
|
|
556
567
|
color: #6c6c6c;
|
|
@@ -2314,7 +2325,7 @@ body.twm-dt-col-resizing {
|
|
|
2314
2325
|
border: 1px solid var(--surface-3);
|
|
2315
2326
|
border-radius: var(--radius-md);
|
|
2316
2327
|
box-shadow: 0 6px 24px rgba(0,0,0,0.45);
|
|
2317
|
-
z-index:
|
|
2328
|
+
z-index: var(--z-context-menu);
|
|
2318
2329
|
display: none;
|
|
2319
2330
|
pointer-events: auto;
|
|
2320
2331
|
min-width: 180px;
|
|
@@ -10684,6 +10695,26 @@ button.twm-alerts__ref:hover { text-decoration: underline; }
|
|
|
10684
10695
|
margin: var(--space-xs) var(--space-md);
|
|
10685
10696
|
background: var(--surface-3);
|
|
10686
10697
|
}
|
|
10698
|
+
/* The hamburger (STORY-0133, `style: 'hamburger'`): one icon button in place
|
|
10699
|
+
* of the titles, the size of the top bar's other icon buttons
|
|
10700
|
+
* (.twm-panel-toggle-btn: a 22px box, an --font-size-xl glyph). Its menu
|
|
10701
|
+
* lists the menus, each flying out its items. */
|
|
10702
|
+
.twm-menubar--hamburger {
|
|
10703
|
+
align-items: center;
|
|
10704
|
+
}
|
|
10705
|
+
.twm-menubar__title--icon {
|
|
10706
|
+
display: inline-flex;
|
|
10707
|
+
align-items: center;
|
|
10708
|
+
justify-content: center;
|
|
10709
|
+
width: 22px;
|
|
10710
|
+
height: 22px;
|
|
10711
|
+
padding: 0;
|
|
10712
|
+
color: var(--text-secondary);
|
|
10713
|
+
}
|
|
10714
|
+
.twm-menubar__title--icon .material-symbols-outlined {
|
|
10715
|
+
font-size: var(--font-size-xl);
|
|
10716
|
+
line-height: 1;
|
|
10717
|
+
}
|
|
10687
10718
|
/* ══ end MENU BAR ══ */
|
|
10688
10719
|
|
|
10689
10720
|
/* ══ TOGGLE ══════════════════════════════════════════════════════════
|
package/css/reset.css
CHANGED
|
File without changes
|
package/css/tokens.css
CHANGED
|
@@ -137,6 +137,9 @@
|
|
|
137
137
|
--z-popover: 200;
|
|
138
138
|
--z-modal: 1000;
|
|
139
139
|
--z-toast: 10000;
|
|
140
|
+
/* A context menu is what the pointer just asked for: over everything,
|
|
141
|
+
toasts and managed windows included (a right-click on a toast). */
|
|
142
|
+
--z-context-menu: 10100;
|
|
140
143
|
/* What opens FROM a managed window and must draw over it: managed windows
|
|
141
144
|
stack from 6000 to 6999 (managed_window.js), so a popover at
|
|
142
145
|
--z-popover would open behind the window that opened it. */
|
package/dist/canvas.js
CHANGED
|
File without changes
|
package/dist/canvas.js.map
CHANGED
|
File without changes
|
package/dist/chunk-3PHCPZHT.js
CHANGED
|
File without changes
|
|
File without changes
|
package/dist/chunk-FOOS3T5L.js
CHANGED
|
File without changes
|
|
File without changes
|
package/dist/chunk-GOQLR5WR.js
CHANGED
|
File without changes
|
|
File without changes
|
|
@@ -1389,6 +1389,8 @@ function installHelpShortcut({ target = document } = {}) {
|
|
|
1389
1389
|
var SEL_TITLE = ".twm-menubar__title";
|
|
1390
1390
|
var SEL_ITEM = ".twm-menubar__item";
|
|
1391
1391
|
var SEL_MENU = ".twm-menubar__menu";
|
|
1392
|
+
var STYLES = ["bar", "hamburger"];
|
|
1393
|
+
var HAMBURGER = "twm-menubar:hamburger";
|
|
1392
1394
|
function createMenuBar(el, opts) {
|
|
1393
1395
|
return new MenuBar(el, opts);
|
|
1394
1396
|
}
|
|
@@ -1400,16 +1402,22 @@ var MenuBar = class {
|
|
|
1400
1402
|
* @param {Function} [opts.onAction] `(id, { item, checked }) => void`
|
|
1401
1403
|
* @param {string} [opts.label] the bar's accessible name ('Menu')
|
|
1402
1404
|
* @param {string} [opts.emptyLabel] the disabled row an empty submenu shows ('Empty')
|
|
1405
|
+
* @param {string} [opts.style] 'bar' (a title per menu, the default) or 'hamburger' (one button)
|
|
1406
|
+
* @param {string} [opts.icon] the hamburger's Material Symbols icon ('menu')
|
|
1403
1407
|
*/
|
|
1404
|
-
constructor(el, { menus, onAction = null, label = "Menu", emptyLabel = "Empty" } = {}) {
|
|
1408
|
+
constructor(el, { menus, onAction = null, label = "Menu", emptyLabel = "Empty", style = "bar", icon = "menu" } = {}) {
|
|
1405
1409
|
if (!el || typeof el.appendChild !== "function") {
|
|
1406
1410
|
throw new TypeError("createMenuBar: `el` must be an element");
|
|
1407
1411
|
}
|
|
1408
1412
|
_validateMenus(menus);
|
|
1413
|
+
_validateStyle(style);
|
|
1409
1414
|
this.el = el;
|
|
1410
1415
|
this.menus = menus;
|
|
1411
1416
|
this._onAction = typeof onAction === "function" ? onAction : null;
|
|
1412
1417
|
this._emptyLabel = emptyLabel;
|
|
1418
|
+
this._label = label;
|
|
1419
|
+
this._icon = icon;
|
|
1420
|
+
this._style = style;
|
|
1413
1421
|
this._doc = el.ownerDocument;
|
|
1414
1422
|
this._disabled = /* @__PURE__ */ new Map();
|
|
1415
1423
|
this._checked = /* @__PURE__ */ new Map();
|
|
@@ -1420,26 +1428,10 @@ var MenuBar = class {
|
|
|
1420
1428
|
this._active = false;
|
|
1421
1429
|
this._returnTo = null;
|
|
1422
1430
|
this._altArmed = false;
|
|
1423
|
-
el.innerHTML = "";
|
|
1424
1431
|
el.classList.add("twm-menubar");
|
|
1425
1432
|
el.setAttribute("role", "menubar");
|
|
1426
1433
|
el.setAttribute("aria-label", label);
|
|
1427
|
-
this.
|
|
1428
|
-
const entry = this._doc.createElement("div");
|
|
1429
|
-
entry.className = "twm-menubar__entry";
|
|
1430
|
-
entry.setAttribute("role", "none");
|
|
1431
|
-
const btn = this._doc.createElement("button");
|
|
1432
|
-
btn.type = "button";
|
|
1433
|
-
btn.className = "twm-menubar__title";
|
|
1434
|
-
btn.setAttribute("role", "menuitem");
|
|
1435
|
-
btn.setAttribute("aria-haspopup", "menu");
|
|
1436
|
-
btn.setAttribute("aria-expanded", "false");
|
|
1437
|
-
btn.tabIndex = i === 0 ? 0 : -1;
|
|
1438
|
-
btn.textContent = m.label;
|
|
1439
|
-
entry.appendChild(btn);
|
|
1440
|
-
el.appendChild(entry);
|
|
1441
|
-
return btn;
|
|
1442
|
-
});
|
|
1434
|
+
this._renderTitles();
|
|
1443
1435
|
this._h = {
|
|
1444
1436
|
mousedown: (e) => this._onMouseDown(e),
|
|
1445
1437
|
click: (e) => this._onClick(e),
|
|
@@ -1473,12 +1465,37 @@ var MenuBar = class {
|
|
|
1473
1465
|
isOpen() {
|
|
1474
1466
|
return this._openIdx >= 0;
|
|
1475
1467
|
}
|
|
1476
|
-
/** Open the menu with this id (focus on its title, or on its first item).
|
|
1468
|
+
/** Open the menu with this id (focus on its title, or on its first item).
|
|
1469
|
+
* A hamburger opens with that menu flown out (focus on its row, or on
|
|
1470
|
+
* the menu's first item). */
|
|
1477
1471
|
open(menuId, { focusItem = false } = {}) {
|
|
1478
1472
|
const i = this.menus.findIndex((m) => m.id === menuId);
|
|
1479
1473
|
if (i < 0) return;
|
|
1480
1474
|
this._enter();
|
|
1481
|
-
this.
|
|
1475
|
+
if (this._style !== "hamburger") {
|
|
1476
|
+
this._open(i, focusItem ? "first" : null);
|
|
1477
|
+
return;
|
|
1478
|
+
}
|
|
1479
|
+
this._open(0, null);
|
|
1480
|
+
const row = this._itemsIn(this._stack[0].menu).find((b) => this._models.get(b)?.id === `${HAMBURGER}:${menuId}`);
|
|
1481
|
+
if (!row) return;
|
|
1482
|
+
row.focus({ preventScroll: true });
|
|
1483
|
+
this._openSub(row, focusItem ? "first" : null);
|
|
1484
|
+
}
|
|
1485
|
+
/** 'bar' or 'hamburger'. */
|
|
1486
|
+
get style() {
|
|
1487
|
+
return this._style;
|
|
1488
|
+
}
|
|
1489
|
+
/** Draw the menus as a bar or as one hamburger button. Whatever is open
|
|
1490
|
+
* closes; the model and every setEnabled / setChecked stay. */
|
|
1491
|
+
setStyle(style) {
|
|
1492
|
+
_validateStyle(style);
|
|
1493
|
+
if (style === this._style) return;
|
|
1494
|
+
const hadFocus = this.el.contains(this._doc.activeElement);
|
|
1495
|
+
this._deactivate();
|
|
1496
|
+
this._style = style;
|
|
1497
|
+
this._renderTitles();
|
|
1498
|
+
if (hadFocus) this._focusTitle(0);
|
|
1482
1499
|
}
|
|
1483
1500
|
/** Close every open menu. Focus stays in the bar if it was there. */
|
|
1484
1501
|
close() {
|
|
@@ -1546,7 +1563,7 @@ var MenuBar = class {
|
|
|
1546
1563
|
this._doc.removeEventListener("mousedown", this._h.docMousedown, true);
|
|
1547
1564
|
this._doc.defaultView?.removeEventListener("blur", this._h.winBlur);
|
|
1548
1565
|
this.el.innerHTML = "";
|
|
1549
|
-
this.el.classList.remove("twm-menubar");
|
|
1566
|
+
this.el.classList.remove("twm-menubar", "twm-menubar--hamburger");
|
|
1550
1567
|
this.el.removeAttribute("role");
|
|
1551
1568
|
this.el.removeAttribute("aria-label");
|
|
1552
1569
|
}
|
|
@@ -1616,6 +1633,48 @@ var MenuBar = class {
|
|
|
1616
1633
|
btn.setAttribute("aria-checked", this._isChecked(item) ? "true" : "false");
|
|
1617
1634
|
}
|
|
1618
1635
|
}
|
|
1636
|
+
// ── titles ────────────────────────────────────────────────────────
|
|
1637
|
+
/** The titles for the current style. `_top` is what they open: the
|
|
1638
|
+
* menus themselves, or the hamburger's one menu that lists them. */
|
|
1639
|
+
_renderTitles() {
|
|
1640
|
+
const d = this._doc;
|
|
1641
|
+
const burger = this._style === "hamburger";
|
|
1642
|
+
this.el.innerHTML = "";
|
|
1643
|
+
this.el.classList.toggle("twm-menubar--hamburger", burger);
|
|
1644
|
+
this._top = burger ? [{ id: HAMBURGER, label: this._label, items: this.menus.map((m) => ({
|
|
1645
|
+
id: `${HAMBURGER}:${m.id}`,
|
|
1646
|
+
label: m.label,
|
|
1647
|
+
submenu: m.items
|
|
1648
|
+
})) }] : this.menus;
|
|
1649
|
+
this._titles = this._top.map((m, i) => {
|
|
1650
|
+
const entry = d.createElement("div");
|
|
1651
|
+
entry.className = "twm-menubar__entry";
|
|
1652
|
+
entry.setAttribute("role", "none");
|
|
1653
|
+
const btn = d.createElement("button");
|
|
1654
|
+
btn.type = "button";
|
|
1655
|
+
btn.className = "twm-menubar__title";
|
|
1656
|
+
btn.setAttribute("role", "menuitem");
|
|
1657
|
+
btn.setAttribute("aria-haspopup", "menu");
|
|
1658
|
+
btn.setAttribute("aria-expanded", "false");
|
|
1659
|
+
btn.tabIndex = i === 0 ? 0 : -1;
|
|
1660
|
+
if (burger) {
|
|
1661
|
+
btn.classList.add("twm-menubar__title--icon", "twm-has-tooltip");
|
|
1662
|
+
btn.setAttribute("aria-label", m.label);
|
|
1663
|
+
btn.dataset.tooltip = m.label;
|
|
1664
|
+
btn.dataset.tooltipPlacement = "bottom";
|
|
1665
|
+
const icon = d.createElement("span");
|
|
1666
|
+
icon.className = "material-symbols-outlined";
|
|
1667
|
+
icon.setAttribute("aria-hidden", "true");
|
|
1668
|
+
icon.textContent = this._icon;
|
|
1669
|
+
btn.appendChild(icon);
|
|
1670
|
+
} else {
|
|
1671
|
+
btn.textContent = m.label;
|
|
1672
|
+
}
|
|
1673
|
+
entry.appendChild(btn);
|
|
1674
|
+
this.el.appendChild(entry);
|
|
1675
|
+
return btn;
|
|
1676
|
+
});
|
|
1677
|
+
}
|
|
1619
1678
|
// ── open / close ──────────────────────────────────────────────────
|
|
1620
1679
|
_setRoving(i) {
|
|
1621
1680
|
this._titles.forEach((t, j) => {
|
|
@@ -1652,7 +1711,7 @@ var MenuBar = class {
|
|
|
1652
1711
|
i = (i % n + n) % n;
|
|
1653
1712
|
this._focusTitle(i);
|
|
1654
1713
|
this._closeAll();
|
|
1655
|
-
const m = this.
|
|
1714
|
+
const m = this._top[i];
|
|
1656
1715
|
const title = this._titles[i];
|
|
1657
1716
|
const menu = this._buildMenu(m.items, m.label);
|
|
1658
1717
|
title.parentElement.appendChild(menu);
|
|
@@ -1875,6 +1934,7 @@ var MenuBar = class {
|
|
|
1875
1934
|
_titleKey(key, i) {
|
|
1876
1935
|
const n = this._titles.length;
|
|
1877
1936
|
const open = this._openIdx >= 0;
|
|
1937
|
+
if (n === 1 && (key === "ArrowRight" || key === "ArrowLeft" || key === "Home" || key === "End")) return true;
|
|
1878
1938
|
switch (key) {
|
|
1879
1939
|
case "ArrowRight":
|
|
1880
1940
|
open ? this._open(i + 1, null) : this._focusTitle((i + 1) % n);
|
|
@@ -1934,11 +1994,11 @@ var MenuBar = class {
|
|
|
1934
1994
|
return true;
|
|
1935
1995
|
case "ArrowRight":
|
|
1936
1996
|
if (item?.submenu != null && !this._isDisabled(item)) this._openSub(btn, "first");
|
|
1937
|
-
else this._open(this._openIdx + 1, "first");
|
|
1997
|
+
else if (this._titles.length > 1) this._open(this._openIdx + 1, "first");
|
|
1938
1998
|
return true;
|
|
1939
1999
|
case "ArrowLeft":
|
|
1940
2000
|
if (level > 0) this._closeFrom(level);
|
|
1941
|
-
else this._open(this._openIdx - 1, "first");
|
|
2001
|
+
else if (this._titles.length > 1) this._open(this._openIdx - 1, "first");
|
|
1942
2002
|
return true;
|
|
1943
2003
|
case "Enter":
|
|
1944
2004
|
case " ":
|
|
@@ -1991,6 +2051,11 @@ function _kind(item) {
|
|
|
1991
2051
|
if (typeof item.checked === "boolean") return "menuitemcheckbox";
|
|
1992
2052
|
return "menuitem";
|
|
1993
2053
|
}
|
|
2054
|
+
function _validateStyle(style) {
|
|
2055
|
+
if (!STYLES.includes(style)) {
|
|
2056
|
+
throw new TypeError(`createMenuBar: \`style\` must be ${STYLES.map((s) => `'${s}'`).join(" or ")}`);
|
|
2057
|
+
}
|
|
2058
|
+
}
|
|
1994
2059
|
function _validateMenus(menus) {
|
|
1995
2060
|
if (!Array.isArray(menus) || !menus.length) {
|
|
1996
2061
|
throw new TypeError("createMenuBar: `menus` must be a non-empty array");
|
|
@@ -2038,4 +2103,4 @@ export {
|
|
|
2038
2103
|
createMenuBar,
|
|
2039
2104
|
MenuBar
|
|
2040
2105
|
};
|
|
2041
|
-
//# sourceMappingURL=chunk-
|
|
2106
|
+
//# sourceMappingURL=chunk-HKPB6OFA.js.map
|