flexdesk 0.4.3 → 0.4.5

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/dist/widgets.js CHANGED
@@ -21,7 +21,7 @@ import {
21
21
  import {
22
22
  DataTable,
23
23
  createRafResizeObserver
24
- } from "./chunk-P4AALM3A.js";
24
+ } from "./chunk-BIAOGX6K.js";
25
25
  import {
26
26
  ManagedWindow
27
27
  } from "./chunk-LH5TSOZW.js";
@@ -1661,6 +1661,103 @@ var AutocompleteField = class {
1661
1661
  }
1662
1662
  };
1663
1663
 
1664
+ // src/ui/components/column_fit.js
1665
+ var COLUMN_FIT = Object.freeze({
1666
+ /** Absolute floor, and the drag-resize minimum. */
1667
+ FLOOR: 40,
1668
+ /** Sub-pixel safety against an ellipsis on content that exactly fits. */
1669
+ PAD: 2,
1670
+ /** A column whose full width reaches this is free text. */
1671
+ TEXT_AT: 240,
1672
+ /** A text column's starting share when room allows it. */
1673
+ TEXT_MIN: 200,
1674
+ /** How far a text column shrinks before short columns go below `typical`. */
1675
+ TEXT_FLOOR: 120,
1676
+ /** How far a short column shrinks before the table scrolls. */
1677
+ SHORT_FLOOR: 56
1678
+ });
1679
+ function fitColumns(columns, avail) {
1680
+ const { FLOOR, PAD, TEXT_AT, TEXT_MIN, TEXT_FLOOR, SHORT_FLOOR } = COLUMN_FIT;
1681
+ const n = columns.length;
1682
+ const cols = columns.map((c) => {
1683
+ const header = Math.max(0, Number(c.header) || 0);
1684
+ const natural = Math.max(0, Number(c.natural) || 0);
1685
+ const full = Math.max(FLOOR, Math.ceil(Math.max(natural, header) + PAD));
1686
+ const typical = Math.min(full, Math.max(FLOOR, Math.ceil(Math.max(
1687
+ Number.isFinite(c.typical) ? c.typical : natural,
1688
+ header
1689
+ ) + PAD)));
1690
+ const pinned = Number.isFinite(c.pinned) ? Math.max(FLOOR, Math.round(c.pinned)) : null;
1691
+ const text2 = pinned == null && (typeof c.text === "boolean" ? c.text : full >= TEXT_AT);
1692
+ return { full, typical, pinned, text: text2 };
1693
+ });
1694
+ const text = [];
1695
+ const short = [];
1696
+ cols.forEach((c, i) => {
1697
+ if (c.pinned == null) (c.text ? text : short).push(i);
1698
+ });
1699
+ if (!(avail > 1)) return cols.map((c) => c.pinned != null ? c.pinned : c.full);
1700
+ const widths = cols.map((c) => {
1701
+ if (c.pinned != null) return c.pinned;
1702
+ return c.text ? Math.min(c.full, TEXT_MIN) : c.full;
1703
+ });
1704
+ const total = () => widths.reduce((a, b) => a + b, 0);
1705
+ let slack = avail - total();
1706
+ if (slack >= 0) {
1707
+ slack = raise(widths, text, (i) => cols[i].full, slack);
1708
+ if (slack > 0) {
1709
+ if (text.length) text.forEach((i) => {
1710
+ widths[i] += slack / text.length;
1711
+ });
1712
+ else widths[short.length ? short[short.length - 1] : n - 1] += slack;
1713
+ }
1714
+ return widths;
1715
+ }
1716
+ const steps = [
1717
+ [short, (i) => cols[i].typical],
1718
+ [text, () => TEXT_FLOOR],
1719
+ [short, (i) => Math.min(cols[i].typical, SHORT_FLOOR)],
1720
+ [text, () => FLOOR * 2]
1721
+ ];
1722
+ for (const [idxs, low] of steps) {
1723
+ const over = total() - avail;
1724
+ if (over <= 1e-6) break;
1725
+ lowerTo(widths, idxs, low, over);
1726
+ }
1727
+ return widths;
1728
+ }
1729
+ function raise(widths, idxs, target, slack) {
1730
+ if (!(slack > 0)) return slack;
1731
+ const wants = idxs.map((i) => Math.max(0, target(i) - widths[i]));
1732
+ const need = wants.reduce((a, b) => a + b, 0);
1733
+ if (!(need > 0)) return slack;
1734
+ const give = Math.min(slack, need);
1735
+ idxs.forEach((i, k) => {
1736
+ widths[i] += give * wants[k] / need;
1737
+ });
1738
+ return slack - give;
1739
+ }
1740
+ function lowerTo(widths, idxs, low, over) {
1741
+ const floorOf = (i) => Math.min(widths[i], Math.max(0, low(i)));
1742
+ const cand = idxs.filter((i) => widths[i] > floorOf(i));
1743
+ if (!cand.length || over <= 0) return;
1744
+ const floors = new Map(cand.map((i) => [i, floorOf(i)]));
1745
+ const capacity = cand.reduce((a, i) => a + widths[i] - floors.get(i), 0);
1746
+ if (capacity <= over) {
1747
+ for (const i of cand) widths[i] = floors.get(i);
1748
+ return;
1749
+ }
1750
+ const cutAt = (level) => cand.reduce((a, i) => a + Math.max(0, widths[i] - Math.max(floors.get(i), level)), 0);
1751
+ let lo = 0;
1752
+ let hi = Math.max(...cand.map((i) => widths[i]));
1753
+ for (let k = 0; k < 64; k++) {
1754
+ const mid = (lo + hi) / 2;
1755
+ if (cutAt(mid) > over) lo = mid;
1756
+ else hi = mid;
1757
+ }
1758
+ for (const i of cand) widths[i] = Math.min(widths[i], Math.max(floors.get(i), hi));
1759
+ }
1760
+
1664
1761
  // src/ui/components/computing_status_window.js
1665
1762
  var _activeWindow = null;
1666
1763
  function showComputingWindow({ title = "Computing...", message = "", icon = "hourglass_top", onCancel } = {}) {
@@ -4750,6 +4847,233 @@ var NotificationCenter = class _NotificationCenter extends ComponentBase {
4750
4847
  };
4751
4848
  NotificationCenter.SEVERITIES = SEVERITIES;
4752
4849
 
4850
+ // src/ui/utils/auto_scrollbars.js
4851
+ var LAYER_ID = "twm-autoscroll-layer";
4852
+ var ROOT_CLASS = "twm-autoscroll";
4853
+ var HIDE_AFTER_MS = 900;
4854
+ var MIN_THUMB = 30;
4855
+ var BAR = 6;
4856
+ function thumbGeometry(scrollSize, clientSize, scrollPos, trackLen) {
4857
+ const max = scrollSize - clientSize;
4858
+ if (!(max > 1) || !(trackLen > 0)) return null;
4859
+ const size = Math.min(trackLen, Math.max(MIN_THUMB, trackLen * clientSize / scrollSize));
4860
+ const pos = (trackLen - size) * Math.min(1, Math.max(0, scrollPos / max));
4861
+ return { size, pos };
4862
+ }
4863
+ function scrollsOn(el, axis) {
4864
+ if (!(el instanceof Element)) return false;
4865
+ const cs = getComputedStyle(el);
4866
+ const overflow = axis === "y" ? cs.overflowY : cs.overflowX;
4867
+ if (overflow !== "auto" && overflow !== "scroll" && !(el.tagName === "TEXTAREA" && overflow !== "hidden")) return false;
4868
+ return axis === "y" ? el.scrollHeight - el.clientHeight > 1 : el.scrollWidth - el.clientWidth > 1;
4869
+ }
4870
+ function installAutoScrollbars(root = document.body, { exclude = null } = {}) {
4871
+ const doc = root.ownerDocument || document;
4872
+ const win = doc.defaultView || window;
4873
+ root.classList.add(ROOT_CLASS);
4874
+ let layer = doc.getElementById(LAYER_ID);
4875
+ if (!layer) {
4876
+ layer = doc.createElement("div");
4877
+ layer.id = LAYER_ID;
4878
+ layer.className = "twm-autoscroll-layer";
4879
+ doc.body.appendChild(layer);
4880
+ }
4881
+ const managed = /* @__PURE__ */ new Map();
4882
+ let hoverChain = /* @__PURE__ */ new Set();
4883
+ const eligible = (el) => el instanceof Element && root.contains(el) && !el.__overlayScrollbarInstalled && !el.closest?.(".twm-autoscroll-layer") && !(exclude && exclude(el));
4884
+ const makeBar = (el, axis) => {
4885
+ const bar = doc.createElement("div");
4886
+ bar.className = `twm-autoscroll-bar twm-autoscroll-bar--${axis}`;
4887
+ const thumb = doc.createElement("div");
4888
+ thumb.className = "twm-autoscroll-thumb";
4889
+ bar.appendChild(thumb);
4890
+ layer.appendChild(bar);
4891
+ bar.addEventListener("mousedown", (e) => {
4892
+ if (e.target !== bar) return;
4893
+ e.preventDefault();
4894
+ const r = thumb.getBoundingClientRect();
4895
+ const before = axis === "y" ? e.clientY < r.top : e.clientX < r.left;
4896
+ const page = (axis === "y" ? el.clientHeight : el.clientWidth) * 0.9;
4897
+ if (axis === "y") el.scrollTop += before ? -page : page;
4898
+ else el.scrollLeft += before ? -page : page;
4899
+ });
4900
+ thumb.addEventListener("mousedown", (e) => {
4901
+ e.preventDefault();
4902
+ e.stopPropagation();
4903
+ const rec = managed.get(el);
4904
+ if (rec) rec.dragging = true;
4905
+ const start = axis === "y" ? e.clientY : e.clientX;
4906
+ const startScroll = axis === "y" ? el.scrollTop : el.scrollLeft;
4907
+ const trackLen = axis === "y" ? bar.getBoundingClientRect().height : bar.getBoundingClientRect().width;
4908
+ const thumbLen = axis === "y" ? thumb.getBoundingClientRect().height : thumb.getBoundingClientRect().width;
4909
+ const max = axis === "y" ? el.scrollHeight - el.clientHeight : el.scrollWidth - el.clientWidth;
4910
+ const perPx = trackLen > thumbLen ? max / (trackLen - thumbLen) : 0;
4911
+ bar.classList.add("twm-autoscroll-bar--active");
4912
+ const move = (mv) => {
4913
+ const d = (axis === "y" ? mv.clientY : mv.clientX) - start;
4914
+ if (axis === "y") el.scrollTop = startScroll + d * perPx;
4915
+ else el.scrollLeft = startScroll + d * perPx;
4916
+ };
4917
+ const up = () => {
4918
+ doc.removeEventListener("mousemove", move);
4919
+ doc.removeEventListener("mouseup", up);
4920
+ bar.classList.remove("twm-autoscroll-bar--active");
4921
+ if (rec) rec.dragging = false;
4922
+ hideLater(el);
4923
+ };
4924
+ doc.addEventListener("mousemove", move);
4925
+ doc.addEventListener("mouseup", up);
4926
+ });
4927
+ bar.addEventListener("mouseenter", () => {
4928
+ const rec = managed.get(el);
4929
+ if (rec) {
4930
+ rec.onBar = true;
4931
+ show(el);
4932
+ }
4933
+ });
4934
+ bar.addEventListener("mouseleave", () => {
4935
+ const rec = managed.get(el);
4936
+ if (rec) {
4937
+ rec.onBar = false;
4938
+ hideLater(el);
4939
+ }
4940
+ });
4941
+ return { bar, thumb };
4942
+ };
4943
+ const record = (el) => {
4944
+ let rec = managed.get(el);
4945
+ if (!rec) {
4946
+ rec = { v: null, h: null, timer: 0, dragging: false, onBar: false };
4947
+ managed.set(el, rec);
4948
+ }
4949
+ return rec;
4950
+ };
4951
+ const place = (el) => {
4952
+ const rec = managed.get(el);
4953
+ if (!rec) return;
4954
+ if (!el.isConnected) {
4955
+ drop(el);
4956
+ return;
4957
+ }
4958
+ const r = el.getBoundingClientRect();
4959
+ const vw = win.innerWidth;
4960
+ const vh = win.innerHeight;
4961
+ const top = Math.max(0, r.top);
4962
+ const left = Math.max(0, r.left);
4963
+ const bottom = Math.min(vh, r.bottom);
4964
+ const right = Math.min(vw, r.right);
4965
+ const z = el.offsetHeight ? r.height / el.offsetHeight : 1;
4966
+ for (const axis of ["y", "x"]) {
4967
+ const key = axis === "y" ? "v" : "h";
4968
+ const overflows = scrollsOn(el, axis);
4969
+ if (!overflows) {
4970
+ if (rec[key]) rec[key].bar.style.display = "none";
4971
+ continue;
4972
+ }
4973
+ if (!rec[key]) rec[key] = makeBar(el, axis);
4974
+ const { bar, thumb } = rec[key];
4975
+ bar.style.display = "";
4976
+ if (axis === "y") {
4977
+ const len = bottom - top;
4978
+ Object.assign(bar.style, { top: `${top}px`, left: `${right - BAR - 1}px`, height: `${len}px`, width: `${BAR}px` });
4979
+ const g = thumbGeometry(el.scrollHeight * z, el.clientHeight * z, el.scrollTop * z, len);
4980
+ if (!g) {
4981
+ bar.style.display = "none";
4982
+ continue;
4983
+ }
4984
+ Object.assign(thumb.style, { top: `${g.pos}px`, height: `${g.size}px`, left: "0", width: "100%" });
4985
+ } else {
4986
+ const len = right - left;
4987
+ Object.assign(bar.style, { left: `${left}px`, top: `${bottom - BAR - 1}px`, width: `${len}px`, height: `${BAR}px` });
4988
+ const g = thumbGeometry(el.scrollWidth * z, el.clientWidth * z, el.scrollLeft * z, len);
4989
+ if (!g) {
4990
+ bar.style.display = "none";
4991
+ continue;
4992
+ }
4993
+ Object.assign(thumb.style, { left: `${g.pos}px`, width: `${g.size}px`, top: "0", height: "100%" });
4994
+ }
4995
+ }
4996
+ };
4997
+ const setVisible = (el, on) => {
4998
+ const rec = managed.get(el);
4999
+ if (!rec) return;
5000
+ for (const b of [rec.v, rec.h]) if (b) b.bar.classList.toggle("twm-autoscroll-bar--on", on);
5001
+ };
5002
+ const show = (el) => {
5003
+ const rec = record(el);
5004
+ clearTimeout(rec.timer);
5005
+ place(el);
5006
+ setVisible(el, true);
5007
+ };
5008
+ const hideLater = (el) => {
5009
+ const rec = managed.get(el);
5010
+ if (!rec) return;
5011
+ clearTimeout(rec.timer);
5012
+ rec.timer = setTimeout(() => {
5013
+ if (rec.dragging || rec.onBar || hoverChain.has(el)) return;
5014
+ setVisible(el, false);
5015
+ }, HIDE_AFTER_MS);
5016
+ };
5017
+ const drop = (el) => {
5018
+ const rec = managed.get(el);
5019
+ if (!rec) return;
5020
+ clearTimeout(rec.timer);
5021
+ rec.v?.bar.remove();
5022
+ rec.h?.bar.remove();
5023
+ managed.delete(el);
5024
+ };
5025
+ const scrollChain = (target) => {
5026
+ const out = /* @__PURE__ */ new Set();
5027
+ for (let el = target instanceof Element ? target : target?.parentElement; el && el !== doc.documentElement; el = el.parentElement) {
5028
+ if (el.closest?.(".twm-autoscroll-layer")) return out;
5029
+ if (eligible(el) && (scrollsOn(el, "y") || scrollsOn(el, "x"))) out.add(el);
5030
+ if (el === root) break;
5031
+ }
5032
+ return out;
5033
+ };
5034
+ const onOver = (e) => {
5035
+ if (e.target?.closest?.(".twm-autoscroll-layer")) return;
5036
+ const next = scrollChain(e.target);
5037
+ for (const el of hoverChain) if (!next.has(el)) hideLater(el);
5038
+ for (const el of next) show(el);
5039
+ hoverChain = next;
5040
+ };
5041
+ const onLeaveWindow = (e) => {
5042
+ if (e.relatedTarget) return;
5043
+ for (const el of hoverChain) hideLater(el);
5044
+ hoverChain = /* @__PURE__ */ new Set();
5045
+ };
5046
+ const onScroll = (e) => {
5047
+ const el = e.target === doc ? null : e.target;
5048
+ if (el && eligible(el)) {
5049
+ show(el);
5050
+ hideLater(el);
5051
+ }
5052
+ for (const other of managed.keys()) if (other !== el) place(other);
5053
+ };
5054
+ let raf = 0;
5055
+ const onResize = () => {
5056
+ cancelAnimationFrame(raf);
5057
+ raf = requestAnimationFrame(() => {
5058
+ for (const el of managed.keys()) place(el);
5059
+ });
5060
+ };
5061
+ doc.addEventListener("mouseover", onOver, true);
5062
+ doc.addEventListener("mouseout", onLeaveWindow, true);
5063
+ doc.addEventListener("scroll", onScroll, true);
5064
+ win.addEventListener("resize", onResize);
5065
+ return {
5066
+ dispose() {
5067
+ doc.removeEventListener("mouseover", onOver, true);
5068
+ doc.removeEventListener("mouseout", onLeaveWindow, true);
5069
+ doc.removeEventListener("scroll", onScroll, true);
5070
+ win.removeEventListener("resize", onResize);
5071
+ for (const el of [...managed.keys()]) drop(el);
5072
+ root.classList.remove(ROOT_CLASS);
5073
+ }
5074
+ };
5075
+ }
5076
+
4753
5077
  // src/ui/utils/overlay_scrollbar.js
4754
5078
  function normalizeOrientation(value) {
4755
5079
  return String(value || "horizontal").toLowerCase() === "vertical" ? "vertical" : "horizontal";
@@ -5400,6 +5724,7 @@ if (typeof window !== "undefined") {
5400
5724
  export {
5401
5725
  ActionDropdown,
5402
5726
  AutocompleteField,
5727
+ COLUMN_FIT,
5403
5728
  ComponentBase,
5404
5729
  ControllerBase,
5405
5730
  DEFAULT_TYPES,
@@ -5429,10 +5754,12 @@ export {
5429
5754
  createTreeItem,
5430
5755
  createTreeNode,
5431
5756
  filterTree,
5757
+ fitColumns,
5432
5758
  helpCategories,
5433
5759
  helpCopy,
5434
5760
  helpProvider,
5435
5761
  hideContextMenu,
5762
+ installAutoScrollbars,
5436
5763
  installCollapsibleScrollbars,
5437
5764
  installOverlayScrollbar,
5438
5765
  installTabsScrollbars,
@@ -5457,6 +5784,7 @@ export {
5457
5784
  showDeleteConfirmDialog,
5458
5785
  showRunProgressDialog,
5459
5786
  showSelectDialog,
5787
+ thumbGeometry,
5460
5788
  toastError,
5461
5789
  toastInfo,
5462
5790
  toastSuccess,