flexdesk 0.6.3 → 0.7.0

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.
@@ -1,7 +1,7 @@
1
1
  import {
2
2
  DataTable,
3
3
  createRafResizeObserver
4
- } from "./chunk-WLASPRGP.js";
4
+ } from "./chunk-JLCJWCRS.js";
5
5
  import {
6
6
  ManagedWindow
7
7
  } from "./chunk-6JSOVNID.js";
@@ -2370,4 +2370,4 @@ export {
2370
2370
  openPlotPopoutWindow,
2371
2371
  openRawTracesWindow
2372
2372
  };
2373
- //# sourceMappingURL=chunk-WAVLVXYV.js.map
2373
+ //# sourceMappingURL=chunk-WKTYKXWF.js.map
package/dist/flexdesk.css CHANGED
@@ -555,6 +555,18 @@ body.twm-dt-col-resizing {
555
555
  .twm-preview-table.twm-dt-measuring .twm-data-table__filter-row {
556
556
  display: none !important;
557
557
  }
558
+ /* 0.7.0 `filterKinds`: a filter row holding a CONTROL stays in the measure,
559
+ * its text boxes out of it, and each control at its NARROWEST (the widest
560
+ * chip) — so a column is never narrower than one of its chips. */
561
+ .twm-preview-table.twm-dt-measuring .twm-data-table__filter-row.twm-data-table__filter-row--controls {
562
+ display: table-row !important;
563
+ }
564
+ .twm-preview-table.twm-dt-measuring .twm-data-table__filter-row--controls .twm-data-table__filter-wrapper {
565
+ display: none !important;
566
+ }
567
+ .twm-preview-table.twm-dt-measuring th.data-table__filter-cell--control > * {
568
+ width: min-content !important;
569
+ }
558
570
  /* ── C10. The virtual window (`DataTable` with `virtualize`) ─────────────
559
571
  * The column track is a `<colgroup>` (see `_createTable`), so it is the
560
572
  * `<col>` widths the measuring pass has to lift — the same `!important` it
@@ -779,6 +791,145 @@ body.twm-dt-col-resizing {
779
791
  font-size: 16px;
780
792
  line-height: 1;
781
793
  }
794
+ /* ── 0.7.0 DataTable options. Each rule below matches only a class a 0.7.0
795
+ * option sets, so a table that asks for none of them is styled exactly as in
796
+ * 0.6. ─────────────────────────────────────────────────────────────────── */
797
+ /* `rowDetail` — the toggle. Its chevron is drawn by CSS from the icon font
798
+ * (the button carries its class), so the cell's text, its clipped-cell
799
+ * tooltip and a copy stay the cell's own; turned down while open. Negative
800
+ * block margins on a line height of 1: it cannot make its row taller. */
801
+ .twm-preview-table td .twm-dt-detail-toggle {
802
+ display: inline-flex;
803
+ align-items: center;
804
+ justify-content: center;
805
+ width: 18px;
806
+ height: 18px;
807
+ margin: -2px 4px -2px -2px;
808
+ padding: 0;
809
+ border: 0;
810
+ border-radius: 3px;
811
+ background: transparent;
812
+ color: inherit;
813
+ font-size: 16px;
814
+ line-height: 1;
815
+ vertical-align: top;
816
+ cursor: pointer;
817
+ opacity: 0.75;
818
+ }
819
+ .twm-preview-table td .twm-dt-detail-toggle-gap {
820
+ display: inline-block;
821
+ width: 18px;
822
+ margin: 0 4px 0 -2px;
823
+ vertical-align: top;
824
+ }
825
+ .twm-preview-table td .twm-dt-detail-toggle::before {
826
+ content: 'chevron_right';
827
+ transition: transform 0.12s ease;
828
+ }
829
+ .twm-preview-table td .twm-dt-detail-toggle[aria-expanded="true"]::before {
830
+ transform: rotate(90deg);
831
+ }
832
+ .twm-preview-table td .twm-dt-detail-toggle:hover {
833
+ opacity: 1;
834
+ background: rgba(255, 255, 255, 0.08);
835
+ }
836
+ .twm-preview-table td .twm-dt-detail-toggle:focus-visible {
837
+ opacity: 1;
838
+ outline: 1px solid var(--accent-bright, #007acc);
839
+ }
840
+ /* The detail's row: one cell across every column. It is often the body's
841
+ * FIRST cell of its row, so the time column's rules reach it (see the note
842
+ * above the NULL rule) — hence (0,4,3): the wrapper and `tbody` in front. It
843
+ * wraps, it is not clipped, it is not a thing to press (a clickable table's
844
+ * pointer and hover stop at it), and its content does not set the columns'
845
+ * widths (`contain: inline-size`, and it is out of the measuring pass). */
846
+ .twm-data-table-component .twm-preview-table tbody tr.twm-dt-detail-row > td.twm-dt-detail-cell,
847
+ .twm-data-table-component .twm-preview-table tbody tr.twm-dt-detail-row:not(.twm-dt-spacer):not(.data-table__empty-row):hover > td.twm-dt-detail-cell {
848
+ width: auto;
849
+ min-width: 0;
850
+ max-width: none;
851
+ padding: 6px 10px 8px 28px;
852
+ white-space: normal;
853
+ overflow: visible;
854
+ text-overflow: clip;
855
+ font-family: inherit;
856
+ font-weight: normal;
857
+ color: inherit;
858
+ cursor: auto;
859
+ background: var(--twm-dt-detail-bg, rgba(255, 255, 255, 0.025));
860
+ }
861
+ .twm-dt-detail {
862
+ contain: inline-size;
863
+ overflow: auto;
864
+ user-select: text;
865
+ }
866
+ .twm-preview-table.twm-dt-measuring tr.twm-dt-detail-row {
867
+ display: none !important;
868
+ }
869
+ /* `follow` / `refresh()` — a row the last answer did not have, for a moment. */
870
+ @keyframes twm-dt-row-new {
871
+ from { background: var(--twm-dt-new-bg, rgba(0, 122, 204, 0.22)); }
872
+ to { background: transparent; }
873
+ }
874
+ .twm-preview-table tbody tr.twm-dt-row--new > td {
875
+ animation: twm-dt-row-new 1.6s ease-out;
876
+ }
877
+ /* `pagerLabels` — a pager button with its word beside its glyph. */
878
+ .twm-pagination-btn .twm-pagination-btn__label {
879
+ margin-left: 2px;
880
+ font-size: 10px;
881
+ white-space: nowrap;
882
+ }
883
+ /* `filterKinds` — a filter cell holding a control rather than the text box,
884
+ * and the built-in chips. Wraps rather than clipping its control. */
885
+ .twm-preview-table th.data-table__filter-cell--control {
886
+ white-space: normal;
887
+ overflow: visible;
888
+ }
889
+ .twm-dt-filter-chips {
890
+ display: flex;
891
+ flex-wrap: wrap;
892
+ align-items: center;
893
+ gap: 3px;
894
+ }
895
+ .twm-dt-filter-chip {
896
+ display: inline-flex;
897
+ align-items: center;
898
+ gap: 3px;
899
+ height: 20px;
900
+ padding: 0 7px 0 5px;
901
+ border: 1px solid var(--border-default, #3a3a3a);
902
+ border-radius: 10px;
903
+ background: transparent;
904
+ color: #aaa;
905
+ font: inherit;
906
+ font-size: 11px;
907
+ font-weight: normal;
908
+ line-height: 1;
909
+ cursor: pointer;
910
+ }
911
+ .twm-dt-filter-chip:hover {
912
+ background: rgba(255, 255, 255, 0.06);
913
+ }
914
+ .twm-dt-filter-chip:focus-visible {
915
+ outline: 1px solid var(--accent-bright, #007acc);
916
+ }
917
+ .twm-dt-filter-chip.twm-dt-filter-chip--on {
918
+ border-color: var(--accent-bright, #007acc);
919
+ background: rgba(0, 122, 204, 0.18);
920
+ color: #ddd;
921
+ }
922
+ .twm-dt-filter-chip.twm-dt-filter-chip--empty {
923
+ opacity: 0.5;
924
+ }
925
+ .twm-dt-filter-chip .twm-dt-filter-chip__icon {
926
+ font-size: 14px;
927
+ line-height: 1;
928
+ }
929
+ .twm-dt-filter-chip .twm-dt-filter-chip__count {
930
+ color: #888;
931
+ font-variant-numeric: tabular-nums;
932
+ }
782
933
  /* Wizard mode: uniform column widths, no selection */
783
934
  .twm-preview-table-wrap--wizard .twm-preview-table {
784
935
  table-layout: auto;
@@ -7459,6 +7610,188 @@ tr:hover .twm-row-action { opacity: 1; }
7459
7610
  }
7460
7611
 
7461
7612
 
7613
+ /* ══ RECORD LIST & FACT SHEET (0.7.0) ══════════════════════════════════
7614
+ * `createRecordList` (src/ui/components/record_list.js) and
7615
+ * `createFactTable` (src/ui/components/fact_table.js). Neither has a height
7616
+ * of its own: each is exactly as tall as its records, in any parent. */
7617
+
7618
+ /* ── the record list ── */
7619
+ .twm-record-list { display: block; min-width: 0; }
7620
+ .twm-record-list__items {
7621
+ list-style: none;
7622
+ margin: 0;
7623
+ padding: 0;
7624
+ display: flex;
7625
+ flex-direction: column;
7626
+ }
7627
+ /* A record is one flex row that WRAPS: on a narrow host the pills and verbs
7628
+ * go under the name rather than squeezing it to nothing. */
7629
+ .twm-record {
7630
+ display: flex;
7631
+ flex-wrap: wrap;
7632
+ align-items: center;
7633
+ gap: 4px 10px;
7634
+ padding: 7px 6px;
7635
+ border-bottom: 1px solid var(--border-subtle, #2a2a2a);
7636
+ min-width: 0;
7637
+ }
7638
+ .twm-record:last-child { border-bottom: none; }
7639
+ .twm-record__main {
7640
+ flex: 1 1 14em;
7641
+ min-width: 0;
7642
+ display: flex;
7643
+ flex-direction: column;
7644
+ gap: 2px;
7645
+ }
7646
+ .twm-record__name {
7647
+ color: var(--text-primary, #e0e0e0);
7648
+ overflow-wrap: anywhere;
7649
+ }
7650
+ .twm-record__name--mono { font-family: var(--font-family-mono, monospace); font-size: 0.95em; }
7651
+ /* The quiet line. It wraps by default; `facts: 'ellipsis'` keeps it to one
7652
+ * line and puts the whole of it on the line's title. */
7653
+ .twm-record__facts {
7654
+ color: var(--text-muted, #888);
7655
+ font-size: var(--ea-font-body, 11px);
7656
+ overflow-wrap: anywhere;
7657
+ }
7658
+ .twm-record-list--clip .twm-record__facts {
7659
+ white-space: nowrap;
7660
+ overflow: hidden;
7661
+ text-overflow: ellipsis;
7662
+ }
7663
+ .twm-record__error {
7664
+ color: var(--color-danger, #c74e4e);
7665
+ font-size: var(--ea-font-body, 11px);
7666
+ overflow-wrap: anywhere;
7667
+ }
7668
+ /* A refused verb's reason, ON the screen — never only on a tooltip. */
7669
+ .twm-record__refusals { display: flex; flex-direction: column; gap: 1px; }
7670
+ .twm-record__refusal {
7671
+ color: var(--color-warning, #ff9800);
7672
+ font-size: var(--ea-font-small, 10px);
7673
+ overflow-wrap: anywhere;
7674
+ }
7675
+ .twm-record__pills,
7676
+ .twm-record__verbs {
7677
+ flex: 0 0 auto;
7678
+ display: flex;
7679
+ flex-wrap: wrap;
7680
+ align-items: center;
7681
+ justify-content: flex-end;
7682
+ gap: 4px 6px;
7683
+ margin-left: auto;
7684
+ }
7685
+ .twm-record__pill {
7686
+ display: inline-block;
7687
+ padding: 1px 7px;
7688
+ border-radius: var(--radius-pill, 999px);
7689
+ background: var(--surface-3, #3c3c3c);
7690
+ color: var(--text-muted, #888);
7691
+ font-size: var(--ea-font-small, 10px);
7692
+ line-height: 16px;
7693
+ white-space: nowrap;
7694
+ }
7695
+ .twm-record__pill--info { background: rgba(33, 150, 243, 0.16); color: var(--color-info, #2196f3); }
7696
+ .twm-record__pill--success { background: rgba(63, 185, 80, 0.16); color: var(--color-success, #3fb950); }
7697
+ .twm-record__pill--warn { background: rgba(255, 152, 0, 0.16); color: var(--color-warning, #ff9800); }
7698
+ .twm-record__pill--danger { background: rgba(199, 78, 78, 0.18); color: var(--color-danger, #c74e4e); }
7699
+ .twm-record__pill--muted { background: transparent; color: var(--text-dim, #666); box-shadow: inset 0 0 0 1px var(--border-strong, #383838); }
7700
+ .twm-record__verb-icon.material-symbols-outlined { font-size: 14px; line-height: 1; }
7701
+ /* States. A paused or switched-off record dims its words and pills and NOT
7702
+ * its verbs: the verb that brings it back has to stay readable. A dead or
7703
+ * failing one carries the danger colour on its left edge. */
7704
+ .twm-record--state-paused > .twm-record__main,
7705
+ .twm-record--state-paused > .twm-record__pills,
7706
+ .twm-record--state-off > .twm-record__main,
7707
+ .twm-record--state-off > .twm-record__pills,
7708
+ .twm-record--state-dead > .twm-record__main,
7709
+ .twm-record--state-dead > .twm-record__pills { opacity: 0.55; }
7710
+ .twm-record--state-dead,
7711
+ .twm-record--state-error { box-shadow: inset 2px 0 0 0 var(--color-danger, #c74e4e); }
7712
+ /* `activeKey` — the record that is OPEN: the accent on the left edge, as
7713
+ * DataTable's `twm-dt-row--active`. It wins over a state's edge. */
7714
+ .twm-record.twm-record--active { box-shadow: inset 2px 0 0 0 var(--accent-bright, #007acc); }
7715
+ .twm-record-list--clickable .twm-record { cursor: pointer; }
7716
+ .twm-record-list--clickable .twm-record:hover { background: var(--state-hover, rgba(255, 255, 255, 0.05)); }
7717
+ .twm-record:focus { outline: none; }
7718
+ .twm-record:focus-visible {
7719
+ outline: 1px solid var(--accent-bright, #007acc);
7720
+ outline-offset: -1px;
7721
+ }
7722
+ .twm-record-list__empty {
7723
+ margin: 0;
7724
+ padding: 12px 6px;
7725
+ color: var(--text-muted, #888);
7726
+ font-size: var(--ea-font-body, 11px);
7727
+ }
7728
+
7729
+ /* ── the fact sheet ── */
7730
+ .twm-facts {
7731
+ width: 100%;
7732
+ border-collapse: collapse;
7733
+ table-layout: auto;
7734
+ font-size: var(--font-size-sm, 12px);
7735
+ }
7736
+ .twm-facts thead th {
7737
+ text-align: left;
7738
+ font-size: var(--ea-font-small, 10px);
7739
+ font-weight: 600;
7740
+ letter-spacing: 0.06em;
7741
+ text-transform: uppercase;
7742
+ color: var(--text-dim, #666);
7743
+ white-space: nowrap;
7744
+ border-bottom: 1px solid var(--border-default, #303030);
7745
+ padding: 0 12px 6px 0;
7746
+ }
7747
+ /* Every value WRAPS and keeps its own line breaks: nothing is cut off. */
7748
+ .twm-facts tbody td,
7749
+ .twm-facts tbody th {
7750
+ text-align: left;
7751
+ font-weight: normal;
7752
+ border-bottom: 1px solid var(--border-subtle, #2a2a2a);
7753
+ padding: 6px 12px 6px 0;
7754
+ color: var(--text-primary, #e0e0e0);
7755
+ vertical-align: top;
7756
+ white-space: pre-wrap;
7757
+ overflow-wrap: anywhere;
7758
+ }
7759
+ .twm-facts tbody tr:last-child > td,
7760
+ .twm-facts tbody tr:last-child > th { border-bottom: 0; }
7761
+ .twm-facts tbody th.twm-facts__label {
7762
+ color: var(--text-muted, #888);
7763
+ white-space: nowrap;
7764
+ }
7765
+ .twm-facts.twm-facts--wrap-labels tbody th.twm-facts__label { white-space: normal; }
7766
+ /* `wrap: 'words'` — a value wraps at spaces only, and a long word stays
7767
+ * whole: the sheet grows wider and a sideways scroller around it scrolls.
7768
+ * `wrap: 'none'` — a value keeps its own line breaks and no others. */
7769
+ .twm-facts.twm-facts--wrap-words tbody td,
7770
+ .twm-facts.twm-facts--wrap-words tbody th { overflow-wrap: normal; word-break: normal; }
7771
+ .twm-facts.twm-facts--wrap-none tbody td,
7772
+ .twm-facts.twm-facts--wrap-none tbody th { white-space: pre; overflow-wrap: normal; word-break: normal; }
7773
+ .twm-facts.twm-facts--mono tbody td.twm-facts__value,
7774
+ .twm-facts tbody td.twm-facts__mono { font-family: var(--font-family-mono, monospace); font-size: 0.95em; }
7775
+ .twm-facts .twm-facts__num { font-variant-numeric: tabular-nums; white-space: nowrap; }
7776
+ .twm-facts tbody td.twm-facts__null,
7777
+ .twm-facts tbody td.twm-facts__missing { color: var(--text-dim, #666); font-style: italic; }
7778
+ .twm-facts tbody td.twm-facts__arrow {
7779
+ color: var(--text-dim, #666);
7780
+ white-space: nowrap;
7781
+ width: 1%;
7782
+ }
7783
+ .twm-facts tbody tr.twm-facts__row--changed > td.twm-facts__before { color: var(--text-muted, #888); }
7784
+ .twm-facts tbody tr.twm-facts__row--changed > td.twm-facts__arrow { color: var(--color-warning, #ff9800); }
7785
+ .twm-facts tbody tr.twm-facts__row--same > td { color: var(--text-muted, #888); }
7786
+ .twm-facts tbody tr.twm-facts__row--added > td.twm-facts__after { color: var(--color-success, #3fb950); }
7787
+ .twm-facts tbody tr.twm-facts__row--removed > td.twm-facts__before { color: var(--color-danger, #c74e4e); }
7788
+ .twm-facts tbody td.twm-facts__empty {
7789
+ padding: 12px 0;
7790
+ color: var(--text-muted, #888);
7791
+ white-space: normal;
7792
+ }
7793
+ /* ══ end RECORD LIST & FACT SHEET ══ */
7794
+
7462
7795
  /* ══ FLOW · KIT ═══════════════════════════════════════════════════════ */
7463
7796
  /* The shared flow-editor kit (36 §3, §3.12): the settings panel and its
7464
7797
  * fields, the generic widgets, reference chips and the chip input, the two
package/dist/flow.js CHANGED
@@ -3,7 +3,7 @@ import {
3
3
  } from "./chunk-6NG7YVBG.js";
4
4
  import {
5
5
  DataTable
6
- } from "./chunk-WLASPRGP.js";
6
+ } from "./chunk-JLCJWCRS.js";
7
7
  import "./chunk-6JSOVNID.js";
8
8
  import "./chunk-FL5KFNQH.js";
9
9
  import {
@@ -6487,7 +6487,7 @@ function createOutlineEditor(host, options = {}) {
6487
6487
  if (fs.length) row.appendChild(badge(fs));
6488
6488
  item.appendChild(row);
6489
6489
  item.setAttribute("aria-label", [map.startLabel(S), sum].filter(Boolean).join(", "));
6490
- row.addEventListener("click", () => select("flow", { focus: true }));
6490
+ row.addEventListener("click", () => select("flow", { focus: true, picked: true }));
6491
6491
  if (filter) item.classList.add("twm-flow-outline__item--context");
6492
6492
  itemEls.set("flow", item);
6493
6493
  return item;
@@ -6614,7 +6614,7 @@ function createOutlineEditor(host, options = {}) {
6614
6614
  openMenu(item.id, menu);
6615
6615
  });
6616
6616
  }
6617
- row.addEventListener("click", () => select(item.id, { focus: true }));
6617
+ row.addEventListener("click", () => select(item.id, { focus: true, picked: true }));
6618
6618
  return { row, label: [name, type?.label !== name ? type?.label : null, summary].filter(Boolean).join(", ") };
6619
6619
  }
6620
6620
  const offArm = /* @__PURE__ */ new Set();
@@ -6789,7 +6789,7 @@ function createOutlineEditor(host, options = {}) {
6789
6789
  b.tabIndex = current && b.closest('[role="treeitem"]') === current ? 0 : -1;
6790
6790
  }
6791
6791
  }
6792
- function select(id, { focus = false, silent = false } = {}) {
6792
+ function select(id, { focus = false, silent = false, picked = false } = {}) {
6793
6793
  const next = id === null || id === void 0 ? "flow" : id;
6794
6794
  const changed = next !== selected;
6795
6795
  selected = next;
@@ -6800,8 +6800,19 @@ function createOutlineEditor(host, options = {}) {
6800
6800
  }
6801
6801
  void silent;
6802
6802
  if (focus) itemEls.get(selected)?.focus({ preventScroll: false });
6803
+ if (picked) revealSettings();
6803
6804
  if (changed) onSelect?.({ kind: selected === "flow" ? "flow" : "step", id: selected === "flow" ? null : selected });
6804
6805
  }
6806
+ function revealSettings() {
6807
+ if (destroyed) return;
6808
+ const box = body.getBoundingClientRect();
6809
+ if (!box.height) return;
6810
+ const r = settingsHost.getBoundingClientRect();
6811
+ const inside = r.top >= box.top - 1 && r.bottom <= box.bottom + 1;
6812
+ const covers = r.top <= box.top + 1 && r.bottom >= box.bottom - 1;
6813
+ if (inside || covers) return;
6814
+ settingsHost.scrollIntoView?.({ block: "nearest" });
6815
+ }
6805
6816
  function focusSelected() {
6806
6817
  const li = itemEls.get(selected) ?? itemEls.get("flow");
6807
6818
  if (li) li.focus({ preventScroll: true });
@@ -7187,7 +7198,7 @@ function createOutlineEditor(host, options = {}) {
7187
7198
  return apply(r, "flow:step:remove");
7188
7199
  }
7189
7200
  function rename(id) {
7190
- select(id);
7201
+ select(id, { picked: true });
7191
7202
  const input = settingsHost.querySelector("[data-twm-flow-title]");
7192
7203
  if (input) {
7193
7204
  input.focus({ preventScroll: true });
@@ -7203,7 +7214,7 @@ function createOutlineEditor(host, options = {}) {
7203
7214
  function goTo(f) {
7204
7215
  const id = f?.node_id && nodeOf(f.node_id) ? f.node_id : "flow";
7205
7216
  if (reveal(id)) render();
7206
- select(id, { focus: true });
7217
+ select(id, { focus: true, picked: true });
7207
7218
  if (f?.field) panel.focusField(f.field);
7208
7219
  }
7209
7220
  function setFolds(ids) {
@@ -7240,6 +7251,7 @@ function createOutlineEditor(host, options = {}) {
7240
7251
  open: (ev) => {
7241
7252
  if (!inTree(ev) || ev.target.closest("button")) return false;
7242
7253
  const f = settingsHost.querySelector('.twm-flow-panel__fields input, .twm-flow-panel__fields select, .twm-flow-panel__fields textarea, .twm-flow-panel__fields [contenteditable="true"], .twm-flow-panel__fields button') || settingsHost.querySelector("[data-twm-flow-title]");
7254
+ if (f) revealSettings();
7243
7255
  f?.focus({ preventScroll: false });
7244
7256
  return Boolean(f);
7245
7257
  },
@@ -7527,11 +7539,15 @@ function createOutlineEditor(host, options = {}) {
7527
7539
  setStatus(text) {
7528
7540
  statusEl.textContent = text ?? "";
7529
7541
  },
7530
- /** Select a step (unfolding the blocks around it, so it is on the screen), the flow, or nothing. */
7542
+ /**
7543
+ * Select a step (unfolding the blocks around it, so it is on the
7544
+ * screen), the flow, or nothing — and, in a narrow editor whose panel
7545
+ * is scrolled off, bring its settings on screen as a press does.
7546
+ */
7531
7547
  select(id) {
7532
7548
  const want = id === null || id === void 0 ? "flow" : id;
7533
7549
  if (want !== "flow" && reveal(want)) render();
7534
- select(want);
7550
+ select(want, { picked: true });
7535
7551
  },
7536
7552
  focus() {
7537
7553
  focusSelected();