flexdesk 0.17.15 → 0.17.17

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.
Files changed (49) hide show
  1. package/CHANGELOG.md +42 -0
  2. package/css/base.css +236 -5
  3. package/css/flexdesk.css +326 -13
  4. package/css/tokens.css +3 -0
  5. package/dist/charts.js +104 -34
  6. package/dist/charts.js.map +3 -3
  7. package/dist/{chunk-2PM6ZMNS.js → chunk-2Z2ENHR3.js} +2 -2
  8. package/dist/{chunk-AD7FIA3Z.js → chunk-7JI7HHSY.js} +2 -2
  9. package/dist/{chunk-TLIV6QSU.js → chunk-7OL6F2AM.js} +3 -3
  10. package/dist/{chunk-MADMGRX2.js → chunk-PGZ4EHSE.js} +156 -9
  11. package/dist/chunk-PGZ4EHSE.js.map +7 -0
  12. package/dist/{chunk-OEG6NPAN.js → chunk-XJNADRGR.js} +2 -2
  13. package/dist/flexdesk.css +326 -13
  14. package/dist/flow.js +3 -3
  15. package/dist/tiles.js +84 -9
  16. package/dist/tiles.js.map +2 -2
  17. package/dist/tokens.css +3 -0
  18. package/dist/widgets.js +4559 -4091
  19. package/dist/widgets.js.map +4 -4
  20. package/dist/wm.js +212 -40
  21. package/dist/wm.js.map +2 -2
  22. package/docs/README.md +1 -1
  23. package/docs/components/charts.md +70 -3
  24. package/docs/components/forms-and-dialogs.md +61 -0
  25. package/docs/components/menus.md +85 -1
  26. package/docs/components/notifications.md +23 -1
  27. package/docs/components/panels-and-desktops.md +22 -0
  28. package/docs/components/shell.md +91 -0
  29. package/docs/components/tiles.md +37 -0
  30. package/package.json +1 -1
  31. package/src/charts/plot_config_editor.js +125 -29
  32. package/src/tiles/tile_base.js +48 -2
  33. package/src/tiles/tile_grid.js +42 -1
  34. package/src/tiling/kind_taxonomy.js +66 -13
  35. package/src/tiling/shell.js +4 -1
  36. package/src/tiling/wm.js +205 -35
  37. package/src/ui/components/category_picker.js +556 -0
  38. package/src/ui/components/computing_status_window.js +3 -0
  39. package/src/ui/components/confirm_dialog.js +3 -0
  40. package/src/ui/components/managed_window.js +204 -9
  41. package/src/ui/components/notification_history.js +11 -1
  42. package/src/ui/components/wizard.js +4 -1
  43. package/src/ui/notification_center.js +47 -1
  44. package/widgets.js +2 -1
  45. package/dist/chunk-MADMGRX2.js.map +0 -7
  46. /package/dist/{chunk-2PM6ZMNS.js.map → chunk-2Z2ENHR3.js.map} +0 -0
  47. /package/dist/{chunk-AD7FIA3Z.js.map → chunk-7JI7HHSY.js.map} +0 -0
  48. /package/dist/{chunk-TLIV6QSU.js.map → chunk-7OL6F2AM.js.map} +0 -0
  49. /package/dist/{chunk-OEG6NPAN.js.map → chunk-XJNADRGR.js.map} +0 -0
package/CHANGELOG.md CHANGED
@@ -1,5 +1,47 @@
1
1
  # Changelog
2
2
 
3
+ ## 0.17.17 (2026-10-27)
4
+
5
+ A patch release. One additive taxonomy option and notification copying; one
6
+ entry changes what embedders see (listed under "Changed behaviour").
7
+
8
+ ### Added
9
+
10
+ - [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).
11
+ - [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).
12
+
13
+ ### Changed behaviour
14
+
15
+ - 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).
16
+ - 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).
17
+
18
+ ### Removed or renamed exports
19
+
20
+ None. New: `isSinglePerDesktop` on the taxonomy, `wm.desktopMoveRefusal`, `notificationText` (notification_center.js), the `--z-context-menu` custom property.
21
+
22
+ ## 0.17.16 (2026-10-27)
23
+
24
+ A patch release. Two new widgets and options; the other entries change what
25
+ embedders see (listed under "Changed behaviour"). Each entry links to its
26
+ section of the docs.
27
+
28
+ ### Added
29
+
30
+ - [A categorised picker: `CategoryPicker`](docs/components/menus.md#a-categorised-picker-categorypicker-01716): a popover anchored to a trigger, like ActionDropdown, with a search field over categories (colour dot, count), the active category's items (icon or short badge) and a detail pane (description, optional monospace preview, an Add button). Typing filters across categories; arrows, Enter, Tab (cycling field and Add), double-click and Esc work as documented; IME composition is respected; ARIA combobox/listbox with `aria-activedescendant`. Exported from `@flexdesk/widgets` (STORY-0126).
31
+ - [A kind that lives in a window: `windowOnly` and `window`](docs/components/shell.md#a-kind-that-lives-in-a-window-windowonly-and-window-01716): a taxonomy kind can declare `window: { width, height }` and `windowOnly: true`. A window-only kind opens in a managed window from every open path, its window never docks into a tile, and a restored layout drops its tile tabs with one warning; `taxonomy.isWindowOnly` and `windowSize` answer (STORY-0127).
32
+ - [Tile title double-click and configuring marks](docs/components/tiles.md#a-double-click-on-the-title-strip-configures-the-tile-01716): a double-click on a tile's title strip does what its cogwheel does (`configOnDoubleClick`, default on); `grid.setConfiguring(tileId, on)` / `grid.isConfiguring(tileId)` keep any number of tiles marked as being configured (`tile--configuring`), across `setLayout` (STORY-0128).
33
+ - `ManagedWindow` options `persistGeometry` (default true) and `focusOnOpen` (default true; `'window'` focuses the frame), `ManagedWindow.configure({ storageKey, maxSavedWindows })`, `DEFAULT_MAX_SAVED_WINDOWS` (50) and `win.isClosed` (BUG-0053).
34
+ - The plot config editor's `extraSeriesFields` may return an array of field specs `{ label, control | render, hint? }` that the editor lays out on its own label column, and receives `ctx.field(label, control, { hint })` (BUG-0052).
35
+
36
+ ### Changed behaviour
37
+
38
+ - [Windows: closing, focus and Esc](docs/components/forms-and-dialogs.md#windows-closing-focus-and-esc-01716): a closed `ManagedWindow` leaves the registry and releases its content and callbacks (`get(id)` answers null; build a new window to reopen). Saved geometry keeps the 50 most recently used ids (window-manager-minted `twm-mw-*` entries are purged). A new window takes focus (its first field) and gives it back on close; the computing status window does not take focus, and the run-progress dialog focuses its frame, not Stop. Esc closes a modal on top wherever focus is, otherwise the window holding focus, otherwise the topmost modal, and never when the key was already handled (`defaultPrevented`) or composing (BUG-0053).
39
+ - [A plot config series is one block](docs/components/charts.md#a-plot-config-series-is-one-block-and-an-embedders-fields-share-it-01716): each series is a header line (variable, label, remove) and fields on the editor's label column (colour as ColorField, width, dash, stack group, extra fields, overlay). `.twm-plot-config__series-main` is gone; new classes `__series-head`, `__series-fields`, `__slot`, `__hint`, `__field--hinted`. The config objects read and written are unchanged (BUG-0052).
40
+
41
+ ### Removed or renamed exports
42
+
43
+ None. New exports: `CategoryPicker`, `DEFAULT_MAX_SAVED_WINDOWS`. flexdesk.css gains the category picker's classes, `.tile--configuring` and the plot config classes above, and drops `.twm-plot-config__series-main`; it defines no new custom property besides the picker's `--twm-category-picker-color`.
44
+
3
45
  ## 0.17.15 (2026-10-26)
4
46
 
5
47
  A patch release with no API change. Its entries change what embedders see: a top-level tile loses its one-segment breadcrumb strip, every `openForm` row lays its inputs out anew, and a slide-out panel no longer crosses what lies right of its host. Each entry links to its section of the docs.
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: 5000; /* Higher than nodes and selection rectangle */
1863
+ z-index: var(--z-context-menu);
1853
1864
  display: none;
1854
1865
  pointer-events: auto;
1855
1866
  min-width: 180px;
@@ -3344,20 +3355,25 @@ body.twm-window-maximized .twm-resize-handle {
3344
3355
  }
3345
3356
 
3346
3357
  /* Selected — set by `_onConfigClick()` while the config dialog is open, and
3347
- cleared from every sibling by the same handler. It reads `--accent-lighter`
3358
+ cleared from every sibling by the same handler. `--configuring` is the same
3359
+ look set by the embedder through `setConfiguring()` (0.17.16), one per open
3360
+ config window, and no handler clears it. It reads `--accent-lighter`
3348
3361
  (BUG-0045): `--accent-bright` is a border colour on this background and not
3349
3362
  a text one. It was #78b9ff, which no mix of `--accent-bright` with white
3350
3363
  gives exactly; `--accent-lighter` (about #73b6e3) is the nearest. */
3351
- .tile.tile--selected {
3364
+ .tile.tile--selected,
3365
+ .tile.tile--configuring {
3352
3366
  border-color: var(--accent-lighter);
3353
3367
  box-shadow: 0 0 0 2px color-mix(in srgb, var(--accent-lighter) 30%, transparent), var(--shadow-md);
3354
3368
  }
3355
3369
 
3356
- .tile.tile--selected .tile-header {
3370
+ .tile.tile--selected .tile-header,
3371
+ .tile.tile--configuring .tile-header {
3357
3372
  background: color-mix(in srgb, var(--accent-lighter) 10%, transparent);
3358
3373
  }
3359
3374
 
3360
- .tile.tile--selected .tile-title {
3375
+ .tile.tile--selected .tile-title,
3376
+ .tile.tile--configuring .tile-title {
3361
3377
  color: var(--accent-lighter);
3362
3378
  }
3363
3379
 
@@ -3775,6 +3791,215 @@ body.twm-window-maximized .twm-resize-handle {
3775
3791
  text-overflow: ellipsis;
3776
3792
  }
3777
3793
 
3794
+ /* ══ CATEGORY PICKER (STORY-0126) ══════════════════════════════════════
3795
+ `CategoryPicker` (category_picker.js): a search field over three columns —
3796
+ categories, the active category's items, the highlighted item's detail.
3797
+ Placed by `ActionDropdown.position` (inline top/left/max-height), so it is
3798
+ `position: fixed` on --z-over-windows: over the managed window it opened
3799
+ from. It shrinks to the inline max-height and its columns scroll inside.
3800
+ A category's colour arrives as `--twm-category-picker-color` on its rows. */
3801
+ .twm-category-picker {
3802
+ position: fixed;
3803
+ z-index: var(--z-over-windows);
3804
+ display: flex;
3805
+ flex-direction: column;
3806
+ box-sizing: border-box;
3807
+ width: 640px;
3808
+ max-width: calc(100vw - 2 * var(--space-md));
3809
+ height: 440px;
3810
+ background: var(--surface-1);
3811
+ border: 1px solid var(--border-strong);
3812
+ border-radius: var(--radius-lg);
3813
+ box-shadow: var(--shadow-lg);
3814
+ color: var(--text-primary);
3815
+ font-family: inherit;
3816
+ font-size: var(--font-size-md);
3817
+ overflow: hidden;
3818
+ }
3819
+ .twm-category-picker[hidden] {
3820
+ display: none;
3821
+ }
3822
+ .twm-category-picker__search {
3823
+ flex: none;
3824
+ padding: var(--space-md);
3825
+ border-bottom: 1px solid var(--border-default);
3826
+ }
3827
+ .twm-category-picker__input {
3828
+ width: 100%;
3829
+ box-sizing: border-box;
3830
+ padding: var(--space-sm) var(--space-md);
3831
+ background: var(--surface-0);
3832
+ border: 1px solid var(--border-strong);
3833
+ border-radius: var(--radius-sm);
3834
+ color: var(--text-primary);
3835
+ font-family: inherit;
3836
+ font-size: var(--font-size-md);
3837
+ }
3838
+ .twm-category-picker__input:focus {
3839
+ outline: none;
3840
+ border-color: var(--accent-bright);
3841
+ }
3842
+ .twm-category-picker__body {
3843
+ flex: 1 1 auto;
3844
+ min-height: 0;
3845
+ display: flex;
3846
+ }
3847
+ .twm-category-picker__column {
3848
+ flex: none;
3849
+ box-sizing: border-box;
3850
+ padding: var(--space-sm) 0;
3851
+ border-right: 1px solid var(--border-default);
3852
+ overflow-y: auto;
3853
+ }
3854
+ .twm-category-picker__categories {
3855
+ width: 170px;
3856
+ }
3857
+ .twm-category-picker__items {
3858
+ width: 220px;
3859
+ }
3860
+ .twm-category-picker__category,
3861
+ .twm-category-picker__item {
3862
+ display: flex;
3863
+ align-items: center;
3864
+ gap: var(--space-md);
3865
+ width: 100%;
3866
+ box-sizing: border-box;
3867
+ padding: var(--space-sm) var(--space-lg);
3868
+ background: transparent;
3869
+ border: none;
3870
+ color: var(--text-primary);
3871
+ font-family: inherit;
3872
+ font-size: var(--font-size-md);
3873
+ text-align: left;
3874
+ cursor: pointer;
3875
+ }
3876
+ .twm-category-picker__category:hover,
3877
+ .twm-category-picker__item:hover {
3878
+ background: var(--state-hover);
3879
+ }
3880
+ .twm-category-picker__category--active,
3881
+ .twm-category-picker__item--highlighted,
3882
+ .twm-category-picker__category--active:hover,
3883
+ .twm-category-picker__item--highlighted:hover {
3884
+ background: var(--state-selected);
3885
+ }
3886
+ /* The column the arrow keys move in marks its row with an accent edge. */
3887
+ .twm-category-picker__column--current .twm-category-picker__category--active,
3888
+ .twm-category-picker__column--current .twm-category-picker__item--highlighted {
3889
+ box-shadow: inset 2px 0 0 var(--accent-bright);
3890
+ }
3891
+ .twm-category-picker__category--empty {
3892
+ color: var(--text-dim);
3893
+ }
3894
+ .twm-category-picker__dot {
3895
+ flex: none;
3896
+ width: 8px;
3897
+ height: 8px;
3898
+ border-radius: var(--radius-circle);
3899
+ /* background-color, not the shorthand: the colour is the caller's, and a
3900
+ url() in the shorthand would be fetched */
3901
+ background-color: var(--twm-category-picker-color, var(--text-muted));
3902
+ }
3903
+ .twm-category-picker__category-label,
3904
+ .twm-category-picker__item-label {
3905
+ flex: 1 1 auto;
3906
+ min-width: 0;
3907
+ overflow: hidden;
3908
+ white-space: nowrap;
3909
+ text-overflow: ellipsis;
3910
+ }
3911
+ .twm-category-picker__count {
3912
+ flex: none;
3913
+ color: var(--text-muted);
3914
+ font-size: var(--font-size-xs);
3915
+ font-variant-numeric: tabular-nums;
3916
+ }
3917
+ .twm-category-picker__badge,
3918
+ .twm-category-picker__item .twm-category-picker__icon {
3919
+ flex: none;
3920
+ display: flex;
3921
+ align-items: center;
3922
+ justify-content: center;
3923
+ width: 22px;
3924
+ height: 22px;
3925
+ box-sizing: border-box;
3926
+ color: var(--twm-category-picker-color, var(--text-muted));
3927
+ }
3928
+ .twm-category-picker__badge {
3929
+ border: 1px solid var(--twm-category-picker-color, var(--text-muted));
3930
+ border-radius: var(--radius-sm);
3931
+ font-family: var(--font-family-mono);
3932
+ font-size: var(--font-size-xs);
3933
+ font-weight: var(--font-weight-semibold);
3934
+ overflow: hidden;
3935
+ white-space: nowrap;
3936
+ }
3937
+ .twm-category-picker__item .twm-category-picker__icon {
3938
+ font-size: 18px;
3939
+ }
3940
+ /* One category's hits while a query is set: role="group", named by its header. */
3941
+ .twm-category-picker__hits {
3942
+ display: flex;
3943
+ flex-direction: column;
3944
+ }
3945
+ .twm-category-picker__group {
3946
+ display: flex;
3947
+ align-items: center;
3948
+ gap: var(--space-sm);
3949
+ padding: var(--space-md) var(--space-lg) var(--space-xs);
3950
+ color: var(--text-muted);
3951
+ font-size: var(--font-size-xs);
3952
+ text-transform: uppercase;
3953
+ letter-spacing: 0.06em;
3954
+ }
3955
+ .twm-category-picker__empty,
3956
+ .twm-category-picker__detail-empty {
3957
+ padding: var(--space-md) var(--space-lg);
3958
+ color: var(--text-muted);
3959
+ }
3960
+ .twm-category-picker__detail {
3961
+ flex: 1 1 auto;
3962
+ min-width: 0;
3963
+ display: flex;
3964
+ flex-direction: column;
3965
+ gap: var(--space-md);
3966
+ padding: var(--space-xl);
3967
+ overflow-y: auto;
3968
+ }
3969
+ .twm-category-picker__title {
3970
+ color: var(--text-bright);
3971
+ font-size: var(--font-size-xl);
3972
+ font-weight: var(--font-weight-semibold);
3973
+ }
3974
+ .twm-category-picker__description {
3975
+ color: var(--text-secondary);
3976
+ line-height: var(--line-height-normal);
3977
+ }
3978
+ .twm-category-picker__preview-label {
3979
+ margin-top: var(--space-sm);
3980
+ color: var(--text-muted);
3981
+ font-size: var(--font-size-xs);
3982
+ text-transform: uppercase;
3983
+ letter-spacing: 0.06em;
3984
+ }
3985
+ .twm-category-picker__preview {
3986
+ margin: 0;
3987
+ padding: var(--space-md);
3988
+ background: var(--surface-0);
3989
+ border: 1px solid var(--border-default);
3990
+ border-radius: var(--radius-sm);
3991
+ color: var(--text-body);
3992
+ font-family: var(--font-family-mono);
3993
+ font-size: var(--font-size-sm);
3994
+ white-space: pre-wrap;
3995
+ overflow-wrap: anywhere;
3996
+ }
3997
+ .twm-category-picker__add {
3998
+ margin-top: auto;
3999
+ align-self: flex-end;
4000
+ }
4001
+ /* ══ end CATEGORY PICKER ══ */
4002
+
3778
4003
  /* ── from code.css ───────────────────────── */
3779
4004
  /* Code language tabs */
3780
4005
  .twm-code-tabs-header {
@@ -3934,6 +4159,12 @@ body.twm-window-maximized .twm-resize-handle {
3934
4159
  .twm-managed-window:focus-within {
3935
4160
  border-color: #505050;
3936
4161
  }
4162
+ /* BUG-0053. The frame is focusable (tabindex -1) so a press on it keeps focus
4163
+ in the window; the focus-within border above already shows that, so the
4164
+ frame draws no outline of its own. */
4165
+ .twm-managed-window:focus {
4166
+ outline: none;
4167
+ }
3937
4168
  /* Minimize animation class — targets taskbar item via CSS custom properties */
3938
4169
  .twm-managed-window--minimizing {
3939
4170
  transform: translate(var(--mw-target-x, 0px), var(--mw-target-y, 100vh)) scale(var(--mw-target-scale, 0.1));