@skygraph/react 0.5.3 → 0.6.4

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/README.md CHANGED
@@ -1,6 +1,6 @@
1
1
  # @skygraph/react
2
2
 
3
- React adapter for [SkyGraph](https://skygraph.ruslansinkevich.ru/) — 50+ components, hooks and `ConfigProvider` built on the framework-agnostic [`@skygraph/core`](../core) engine. Shares the `.sg-*` CSS contract with the Vue and Angular adapters via [`@skygraph/styles`](../styles).
3
+ React adapter for [SkyGraph](https://skygraph.ruslansinkevich.ru/) — components, hooks and `ConfigProvider` built on the framework-agnostic [`@skygraph/core`](../core) engine. Shares the `.sg-*` CSS contract with the Vue and Angular adapters via [`@skygraph/styles`](../styles).
4
4
 
5
5
  > **Easier path — the meta-package:**
6
6
  >
@@ -33,7 +33,7 @@ export function App() {
33
33
  }
34
34
  ```
35
35
 
36
- ## Components (53 documented)
36
+ ## Components
37
37
 
38
38
  **Data entry:** Button, Input, InputNumber, Textarea, Select, Checkbox, Radio, Switch, Slider, DatePicker, TimePicker, AutoComplete, Rate, Upload, ColorPicker, Cascader, TreeSelect, Mentions
39
39
 
@@ -1596,14 +1596,11 @@ function TableBody(props) {
1596
1596
  onContextMenu({ x: e.clientX, y: e.clientY, items });
1597
1597
  }
1598
1598
  };
1599
- const handleCellCopy = useCallback2(
1600
- async (rowId, colKey, value) => {
1601
- await copyToClipboard(String(value ?? ""));
1602
- setCopiedCell(`${rowId}:${colKey}`);
1603
- setTimeout(() => setCopiedCell(null), 1500);
1604
- },
1605
- []
1606
- );
1599
+ const handleCellCopy = useCallback2(async (rowId, colKey, value) => {
1600
+ await copyToClipboard(String(value ?? ""));
1601
+ setCopiedCell(`${rowId}:${colKey}`);
1602
+ setTimeout(() => setCopiedCell(null), 1500);
1603
+ }, []);
1607
1604
  if (flatRows.length === 0) {
1608
1605
  return /* @__PURE__ */ jsx6(
1609
1606
  "div",
@@ -1668,7 +1665,13 @@ function TableBody(props) {
1668
1665
  {
1669
1666
  className: "sg-table-td sg-table-cell-drag-handle",
1670
1667
  role: "cell",
1671
- style: { cursor: "grab", userSelect: "none", display: "flex", alignItems: "center", justifyContent: "center" },
1668
+ style: {
1669
+ cursor: "grab",
1670
+ userSelect: "none",
1671
+ display: "flex",
1672
+ alignItems: "center",
1673
+ justifyContent: "center"
1674
+ },
1672
1675
  children: "\u283F"
1673
1676
  }
1674
1677
  ),
@@ -1680,10 +1683,24 @@ function TableBody(props) {
1680
1683
  role: "cell",
1681
1684
  onClick: (e) => {
1682
1685
  e.stopPropagation();
1683
- onSelectRow(row.id, row.data);
1686
+ if (e.target === e.currentTarget) {
1687
+ onSelectRow(row.id, row.data);
1688
+ }
1684
1689
  },
1685
- children: rowSelection.type === "radio" ? /* @__PURE__ */ jsx6("input", { type: "radio", checked: !!isSelected, readOnly: true }) : /* @__PURE__ */ jsx6(Checkbox, { checked: !!isSelected, onChange: () => {
1686
- } })
1690
+ children: rowSelection.type === "radio" ? /* @__PURE__ */ jsx6(
1691
+ "input",
1692
+ {
1693
+ type: "radio",
1694
+ checked: !!isSelected,
1695
+ onChange: () => onSelectRow(row.id, row.data)
1696
+ }
1697
+ ) : /* @__PURE__ */ jsx6(
1698
+ Checkbox,
1699
+ {
1700
+ checked: !!isSelected,
1701
+ onChange: () => onSelectRow(row.id, row.data)
1702
+ }
1703
+ )
1687
1704
  }
1688
1705
  ),
1689
1706
  expandable && /* @__PURE__ */ jsx6("div", { className: "sg-table-td sg-table-cell-expand", role: "cell", children: canExpand && /* @__PURE__ */ jsx6(
@@ -1706,10 +1723,8 @@ function TableBody(props) {
1706
1723
  const isFocused = keyboardNavigation && focusedCell?.row === rowIdx && focusedCell?.col === colIndex;
1707
1724
  const isCopied = copiedCell === cellKey;
1708
1725
  const cellStyle = { ...fixedStyle(col) };
1709
- if (span?.colSpan && span.colSpan > 1)
1710
- cellStyle.gridColumn = `span ${span.colSpan}`;
1711
- if (span?.rowSpan && span.rowSpan > 1)
1712
- cellStyle.gridRow = `span ${span.rowSpan}`;
1726
+ if (span?.colSpan && span.colSpan > 1) cellStyle.gridColumn = `span ${span.colSpan}`;
1727
+ if (span?.rowSpan && span.rowSpan > 1) cellStyle.gridRow = `span ${span.rowSpan}`;
1713
1728
  const isFirstCol = colIndex === 0;
1714
1729
  const treeIndent = isTreeMode && isFirstCol ? row.depth * indentSize : 0;
1715
1730
  const cellClsExtra = typeof col.cellClassName === "function" ? col.cellClassName(val, row.data, row.id) : col.cellClassName ?? "";
@@ -2557,6 +2572,13 @@ function useTableState(props) {
2557
2572
  [table, refresh]
2558
2573
  );
2559
2574
  const resizeRef = useRef6(null);
2575
+ const resizeCleanupRef = useRef6(null);
2576
+ useEffect6(
2577
+ () => () => {
2578
+ resizeCleanupRef.current?.();
2579
+ },
2580
+ []
2581
+ );
2560
2582
  const [contextMenu, setContextMenu] = useState7(null);
2561
2583
  const columns = useMemo3(() => {
2562
2584
  const base = hasColumnGroups ? leafColumns : (() => {
@@ -2682,9 +2704,8 @@ function useTableState(props) {
2682
2704
  );
2683
2705
  const handleToggleExpand = (id) => {
2684
2706
  const open = expandedKeys.has(id);
2685
- if (expandable?.onExpand) {
2686
- expandable.onExpand(!open, id);
2687
- } else {
2707
+ expandable?.onExpand?.(!open, id);
2708
+ if (expandable?.expandedKeys == null) {
2688
2709
  setInternalExpanded((prev) => {
2689
2710
  const next = new Set(prev);
2690
2711
  if (open) {
@@ -2760,28 +2781,34 @@ function useTableState(props) {
2760
2781
  const handleResizeStart = (e, colKey) => {
2761
2782
  e.preventDefault();
2762
2783
  e.stopPropagation();
2784
+ resizeCleanupRef.current?.();
2763
2785
  resizeRef.current = {
2764
2786
  col: colKey,
2765
2787
  startX: e.clientX,
2766
2788
  startW: colWidths[colKey] ?? DEFAULT_COL_WIDTH
2767
2789
  };
2768
2790
  const onMove = (ev) => {
2769
- if (!resizeRef.current) return;
2770
- const diff = ev.clientX - resizeRef.current.startX;
2771
- const min = leafColumns.find((c) => c.key === resizeRef.current.col)?.minWidth ?? MIN_COL_WIDTH;
2791
+ const ref = resizeRef.current;
2792
+ if (!ref) return;
2793
+ const diff = ev.clientX - ref.startX;
2794
+ const min = leafColumns.find((c) => c.key === ref.col)?.minWidth ?? MIN_COL_WIDTH;
2795
+ const nextWidth = Math.max(min, ref.startW + diff);
2796
+ const col = ref.col;
2772
2797
  setColWidths((prev) => ({
2773
2798
  ...prev,
2774
- [resizeRef.current.col]: Math.max(min, resizeRef.current.startW + diff)
2799
+ [col]: nextWidth
2775
2800
  }));
2776
- setUserResizedCols(
2777
- (prev) => prev.has(resizeRef.current.col) ? prev : new Set(prev).add(resizeRef.current.col)
2778
- );
2801
+ setUserResizedCols((prev) => prev.has(col) ? prev : new Set(prev).add(col));
2779
2802
  };
2780
- const onUp = () => {
2781
- const ref = resizeRef.current;
2803
+ const cleanup = () => {
2782
2804
  resizeRef.current = null;
2783
2805
  document.removeEventListener("mousemove", onMove);
2784
2806
  document.removeEventListener("mouseup", onUp);
2807
+ resizeCleanupRef.current = null;
2808
+ };
2809
+ const onUp = () => {
2810
+ const ref = resizeRef.current;
2811
+ cleanup();
2785
2812
  if (!ref) return;
2786
2813
  setColWidths((prev) => {
2787
2814
  const w = prev[ref.col];
@@ -2789,6 +2816,7 @@ function useTableState(props) {
2789
2816
  return prev;
2790
2817
  });
2791
2818
  };
2819
+ resizeCleanupRef.current = cleanup;
2792
2820
  document.addEventListener("mousemove", onMove);
2793
2821
  document.addEventListener("mouseup", onUp);
2794
2822
  };
@@ -2809,13 +2837,11 @@ function useTableState(props) {
2809
2837
  setDragOver(null);
2810
2838
  return;
2811
2839
  }
2812
- setColOrder((prev) => {
2813
- const next = prev.filter((k) => k !== dragCol);
2814
- const idx = next.indexOf(targetKey);
2815
- next.splice(idx, 0, dragCol);
2816
- onColumnOrderChange?.(next);
2817
- return next;
2818
- });
2840
+ const next = colOrder.filter((k) => k !== dragCol);
2841
+ const idx = next.indexOf(targetKey);
2842
+ next.splice(idx, 0, dragCol);
2843
+ setColOrder(next);
2844
+ onColumnOrderChange?.(next);
2819
2845
  setDragCol(null);
2820
2846
  setDragOver(null);
2821
2847
  };
@@ -2846,31 +2872,24 @@ function useTableState(props) {
2846
2872
  }));
2847
2873
  table.groupBy(groupBy, aggregates2);
2848
2874
  }, [groupBy, leafColumns, table]);
2849
- const [expandedGroups, setExpandedGroups] = useState7(() => {
2850
- return defaultGroupExpanded ? /* @__PURE__ */ new Set(["__all__"]) : /* @__PURE__ */ new Set();
2851
- });
2875
+ const [expandedGroups, setExpandedGroups] = useState7(() => /* @__PURE__ */ new Set());
2876
+ const allGroupKeysRef = useRef6([]);
2877
+ const groupsSeededRef = useRef6(false);
2852
2878
  const toggleGroupExpand = useCallback3(
2853
2879
  (groupKey) => {
2880
+ const willExpand = !expandedGroups.has(groupKey);
2854
2881
  setExpandedGroups((prev) => {
2855
2882
  const next = new Set(prev);
2856
- const wasExpanded = next.has(groupKey);
2857
- if (wasExpanded) {
2858
- next.delete(groupKey);
2859
- } else {
2860
- next.add(groupKey);
2861
- }
2862
- onGroupExpandChange?.(groupKey, !wasExpanded);
2883
+ if (next.has(groupKey)) next.delete(groupKey);
2884
+ else next.add(groupKey);
2863
2885
  return next;
2864
2886
  });
2887
+ onGroupExpandChange?.(groupKey, willExpand);
2865
2888
  },
2866
- [onGroupExpandChange]
2889
+ [onGroupExpandChange, expandedGroups]
2867
2890
  );
2868
2891
  const expandAllGroups = useCallback3(() => {
2869
- setExpandedGroups((prev) => {
2870
- const next = new Set(prev);
2871
- next.add("__all__");
2872
- return next;
2873
- });
2892
+ setExpandedGroups(new Set(allGroupKeysRef.current));
2874
2893
  }, []);
2875
2894
  const collapseAllGroups = useCallback3(() => {
2876
2895
  setExpandedGroups(/* @__PURE__ */ new Set());
@@ -2963,11 +2982,32 @@ function useTableState(props) {
2963
2982
  }
2964
2983
  return flattenTreeRows(visibleRows, childrenKey, treeExpanded);
2965
2984
  }, [visibleRows, isTreeMode, childrenKey, treeExpanded]);
2985
+ const allGroupKeys = useMemo3(() => {
2986
+ if (!groupBy) return [];
2987
+ const seen = /* @__PURE__ */ new Set();
2988
+ const keys = [];
2989
+ for (const r of baseFlatRows) {
2990
+ const k = String(r.data[groupBy] ?? "Other");
2991
+ if (!seen.has(k)) {
2992
+ seen.add(k);
2993
+ keys.push(k);
2994
+ }
2995
+ }
2996
+ return keys;
2997
+ }, [baseFlatRows, groupBy]);
2998
+ allGroupKeysRef.current = allGroupKeys;
2999
+ useEffect6(() => {
3000
+ groupsSeededRef.current = false;
3001
+ }, [groupBy]);
3002
+ useEffect6(() => {
3003
+ if (!groupBy || !defaultGroupExpanded) return;
3004
+ if (groupsSeededRef.current || allGroupKeys.length === 0) return;
3005
+ groupsSeededRef.current = true;
3006
+ setExpandedGroups(new Set(allGroupKeys));
3007
+ }, [groupBy, defaultGroupExpanded, allGroupKeys]);
2966
3008
  const groupedRows = useMemo3(() => {
2967
3009
  if (!groupBy) return baseFlatRows;
2968
- const allExpanded = expandedGroups.has("__all__");
2969
- const effectiveExpanded = allExpanded ? /* @__PURE__ */ new Set([...expandedGroups, ...baseFlatRows.map((r) => String(r.data[groupBy] ?? "Other"))]) : expandedGroups;
2970
- return groupByColumn(baseFlatRows, groupBy, columns, effectiveExpanded);
3010
+ return groupByColumn(baseFlatRows, groupBy, columns, expandedGroups);
2971
3011
  }, [baseFlatRows, groupBy, columns, expandedGroups]);
2972
3012
  const {
2973
3013
  top: pinnedTop,
@@ -3838,4 +3878,4 @@ export {
3838
3878
  printElement,
3839
3879
  Table
3840
3880
  };
3841
- //# sourceMappingURL=chunk-P4J4PFBG.js.map
3881
+ //# sourceMappingURL=chunk-7AA2JPZB.js.map