@trops/dash-core 0.1.562 → 0.1.564

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/index.js CHANGED
@@ -11715,7 +11715,9 @@ var PanelEditItem = function PanelEditItem(_ref) {
11715
11715
  var workspace = _ref.workspace,
11716
11716
  onUpdate = _ref.onUpdate,
11717
11717
  _ref$item = _ref.item,
11718
- item = _ref$item === void 0 ? null : _ref$item;
11718
+ item = _ref$item === void 0 ? null : _ref$item,
11719
+ _ref$flushRef = _ref.flushRef,
11720
+ flushRef = _ref$flushRef === void 0 ? null : _ref$flushRef;
11719
11721
  var _useState = React.useState(item),
11720
11722
  _useState2 = _slicedToArray(_useState, 2),
11721
11723
  itemSelected = _useState2[0],
@@ -11730,6 +11732,23 @@ var PanelEditItem = function PanelEditItem(_ref) {
11730
11732
  var forceUpdate = React.useCallback(function () {
11731
11733
  return updateState({});
11732
11734
  }, []);
11735
+
11736
+ // Refs that mirror the latest local state. Used by the unmount
11737
+ // cleanup and the flush handler — both run outside the normal
11738
+ // render cycle and can't rely on the closed-over state, since
11739
+ // closures capture state at the moment the function was created.
11740
+ var itemSelectedRef = React.useRef(itemSelected);
11741
+ var workspaceSelectedRef = React.useRef(workspaceSelected);
11742
+ var onUpdateRef = React.useRef(onUpdate);
11743
+ itemSelectedRef.current = itemSelected;
11744
+ workspaceSelectedRef.current = workspaceSelected;
11745
+ onUpdateRef.current = onUpdate;
11746
+
11747
+ // True when local edits have not yet been propagated to the parent.
11748
+ // Set by handleTextChangeCustom, cleared by flushPending. The
11749
+ // unmount cleanup (below) consults this so a tab switch or modal
11750
+ // close doesn't drop the user's last few keystrokes.
11751
+ var dirtyRef = React.useRef(false);
11733
11752
  React.useEffect(function () {
11734
11753
  if (deepEqual(item, itemSelected) === false) {
11735
11754
  setItemSelected(function () {
@@ -11745,13 +11764,55 @@ var PanelEditItem = function PanelEditItem(_ref) {
11745
11764
  }
11746
11765
  // eslint-disable-next-line react-hooks/exhaustive-deps
11747
11766
  }, [workspace, item]);
11748
- function handleUpdate(e, data) {
11749
- var workspaceTemp = WorkspaceModel(workspaceSelected);
11750
- var newLayout = replaceItemInLayout(workspaceTemp.layout, data["id"], data);
11767
+
11768
+ // Build the fresh workspace from the latest local item + propagate
11769
+ // to the parent. Returns `{item, workspace}` so callers (the
11770
+ // modal's Save handler) can read the new workspace synchronously,
11771
+ // sidestepping React's async setState — the parent's
11772
+ // workspaceSelected state won't reflect this call until the next
11773
+ // render, but the caller already has the new value in hand.
11774
+ //
11775
+ // Returns null when there's nothing to flush.
11776
+ function flushPending() {
11777
+ if (!dirtyRef.current) return null;
11778
+ var latestItem = itemSelectedRef.current;
11779
+ var latestWorkspace = workspaceSelectedRef.current;
11780
+ if (!latestItem || !latestWorkspace) return null;
11781
+ var workspaceTemp = WorkspaceModel(latestWorkspace);
11782
+ var newLayout = replaceItemInLayout(workspaceTemp.layout, latestItem["id"], latestItem);
11751
11783
  workspaceTemp.layout = newLayout;
11752
- onUpdate(data, workspaceTemp);
11753
- forceUpdate();
11784
+ dirtyRef.current = false;
11785
+ onUpdateRef.current(latestItem, workspaceTemp);
11786
+ return {
11787
+ item: latestItem,
11788
+ workspace: workspaceTemp
11789
+ };
11754
11790
  }
11791
+
11792
+ // Expose flushPending via the ref the modal passes in. This is how
11793
+ // the modal's Save handler triggers one final propagation before
11794
+ // calling onSaveWorkspace — without it, the modal would save the
11795
+ // workspace as it stood before the user's last typing burst.
11796
+ React.useEffect(function () {
11797
+ if (!flushRef) return undefined;
11798
+ flushRef.current = flushPending;
11799
+ return function () {
11800
+ if (flushRef.current === flushPending) flushRef.current = null;
11801
+ };
11802
+ // eslint-disable-next-line react-hooks/exhaustive-deps
11803
+ }, [flushRef]);
11804
+
11805
+ // Final flush on unmount. Triggers when the user switches sidebar
11806
+ // tabs (the modal conditionally renders only the active section,
11807
+ // so switching unmounts PanelEditItem) or closes the modal without
11808
+ // saving. The parent modal is still mounted at this point, so
11809
+ // calling onUpdate from cleanup is safe.
11810
+ React.useEffect(function () {
11811
+ return function () {
11812
+ if (dirtyRef.current) flushPending();
11813
+ };
11814
+ // eslint-disable-next-line react-hooks/exhaustive-deps
11815
+ }, []);
11755
11816
  function renderCustomSettings() {
11756
11817
  if (itemSelected) {
11757
11818
  var componentConfig = ComponentManager.getComponent(itemSelected.component);
@@ -11760,8 +11821,15 @@ var PanelEditItem = function PanelEditItem(_ref) {
11760
11821
  }
11761
11822
  if ("userConfig" in componentConfig) {
11762
11823
  var userConfig = componentConfig["userConfig"];
11763
- var layoutItem = LayoutModel(itemSelected, workspaceSelected);
11764
- var userPrefs = layoutItem.userPrefs;
11824
+ // Read userPrefs straight off the locally-tracked itemSelected.
11825
+ // LayoutModel() resets `userPrefs` to widgetConfig template
11826
+ // defaults and only merges back `obj.userConfigValues` (the
11827
+ // EnhancedWidgetDropdown add-time field), silently dropping
11828
+ // `obj.userPrefs`. Piping through it on every render strips
11829
+ // the in-flight typed value and snaps the controlled InputText
11830
+ // back to "", which is what made these inputs untypeable —
11831
+ // user typing "airports" was seeing only the last char land.
11832
+ var userPrefs = itemSelected.userPrefs && _typeof(itemSelected.userPrefs) === "object" ? itemSelected.userPrefs : {};
11765
11833
  return Object.keys(userConfig).map(function (key) {
11766
11834
  if (key in userPrefs) {
11767
11835
  var configItem = userConfig[key];
@@ -11782,7 +11850,18 @@ var PanelEditItem = function PanelEditItem(_ref) {
11782
11850
  newItem["userPrefs"] = {};
11783
11851
  }
11784
11852
  newItem["userPrefs"][key] = value;
11785
- handleUpdate(null, newItem);
11853
+ // Update LOCAL state synchronously so the controlled InputText
11854
+ // reflects the typed character on the very next render. The
11855
+ // expensive workspace clone + parent-tree re-render is DEFERRED
11856
+ // until Save (via flushRef) or unmount (tab switch). Pre-defer
11857
+ // behavior: every keystroke deep-cloned the workspace and
11858
+ // re-rendered the whole modal subtree (sidebar + body + footer),
11859
+ // which made even short strings feel sluggish — characters
11860
+ // landed but the input lagged.
11861
+ setItemSelected(function () {
11862
+ return newItem;
11863
+ });
11864
+ dirtyRef.current = true;
11786
11865
  }
11787
11866
  function renderFormItem(displayName, key, instructions, required, value, _onChange, configItem) {
11788
11867
  var _configItem$step;
@@ -14584,6 +14663,11 @@ var LayoutBuilderConfigModal = function LayoutBuilderConfigModal(_ref) {
14584
14663
  var forceUpdate = React.useCallback(function () {
14585
14664
  return updateState({});
14586
14665
  }, []);
14666
+
14667
+ // PanelEditItem defers per-keystroke propagation to keep typing
14668
+ // snappy. This ref lets us trigger one final flush right before
14669
+ // Save so the saved workspace includes any in-flight edits.
14670
+ var panelEditFlushRef = React.useRef(null);
14587
14671
  React.useEffect(function () {
14588
14672
  if (item !== itemSelected) {
14589
14673
  setItemSelected(function () {
@@ -14615,7 +14699,17 @@ var LayoutBuilderConfigModal = function LayoutBuilderConfigModal(_ref) {
14615
14699
  forceUpdate();
14616
14700
  }
14617
14701
  function handleSaveConfig() {
14618
- onSaveWorkspace(workspaceSelected);
14702
+ // Pull any pending edits out of PanelEditItem before saving.
14703
+ // The panel propagates back via onUpdate (which sets our
14704
+ // workspaceSelected state) but setState is async — so we read
14705
+ // the flushed workspace directly from the return value to avoid
14706
+ // saving a stale snapshot on the very first Save after typing.
14707
+ var workspaceToSave = workspaceSelected;
14708
+ if (typeof panelEditFlushRef.current === "function") {
14709
+ var flushed = panelEditFlushRef.current();
14710
+ if (flushed && flushed.workspace) workspaceToSave = flushed.workspace;
14711
+ }
14712
+ onSaveWorkspace(workspaceToSave);
14619
14713
  }
14620
14714
  var sections = itemSelected ? getSections(itemSelected) : [];
14621
14715
  var activeDef = sections.find(function (s) {
@@ -14680,7 +14774,8 @@ var LayoutBuilderConfigModal = function LayoutBuilderConfigModal(_ref) {
14680
14774
  children: [activeSection === "edit" && /*#__PURE__*/jsxRuntime.jsx(PanelEditItem, {
14681
14775
  item: itemSelected,
14682
14776
  onUpdate: handleEditChange,
14683
- workspace: workspaceSelected
14777
+ workspace: workspaceSelected,
14778
+ flushRef: panelEditFlushRef
14684
14779
  }), activeSection === "grid_layout" && /*#__PURE__*/jsxRuntime.jsx(PanelEditItemGrid, {
14685
14780
  item: itemSelected,
14686
14781
  onUpdate: handleEditChange,
@@ -59625,11 +59720,8 @@ function ProvidersTab(_ref5) {
59625
59720
  var topValue = allSame ? ((_selectedRows$ = selectedRows[0]) === null || _selectedRows$ === void 0 ? void 0 : _selectedRows$.resolvedProviderName) || "" : "";
59626
59721
  return /*#__PURE__*/jsxRuntime.jsxs("div", {
59627
59722
  className: "flex flex-row gap-3 h-full min-h-0",
59628
- children: [/*#__PURE__*/jsxRuntime.jsxs(DashReact.Card2, {
59629
- padding: "",
59630
- shadow: "",
59631
- rounded: "rounded-lg",
59632
- className: "w-56 flex-shrink-0 overflow-hidden flex flex-col",
59723
+ children: [/*#__PURE__*/jsxRuntime.jsxs("div", {
59724
+ className: "w-56 flex-shrink-0 overflow-hidden flex flex-col border-r border-white/10",
59633
59725
  children: [/*#__PURE__*/jsxRuntime.jsx("div", {
59634
59726
  className: "px-3 py-2 text-xs font-semibold opacity-50 uppercase tracking-wider",
59635
59727
  children: "Provider Types"
@@ -59668,10 +59760,7 @@ function ProvidersTab(_ref5) {
59668
59760
  }, providerType);
59669
59761
  })
59670
59762
  })]
59671
- }), /*#__PURE__*/jsxRuntime.jsx(DashReact.Card2, {
59672
- padding: "",
59673
- shadow: "",
59674
- rounded: "rounded-lg",
59763
+ }), /*#__PURE__*/jsxRuntime.jsx("div", {
59675
59764
  className: "flex-1 min-w-0 overflow-hidden flex flex-col",
59676
59765
  children: selectedType ? /*#__PURE__*/jsxRuntime.jsxs(jsxRuntime.Fragment, {
59677
59766
  children: [/*#__PURE__*/jsxRuntime.jsxs("div", {