@morze/ui 0.2.6 → 0.2.7

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
@@ -449,7 +449,12 @@ What it does:
449
449
  and the floating bar can escalate to "all N matching" (in that mode a bulk
450
450
  action must travel with the query, not with a list of ids).
451
451
  - **Columns** — visibility, order (drag and drop plus arrows for the keyboard)
452
- and pinning; all of it saved to `localStorage` under `persistKey`.
452
+ and pinning; all of it saved to `localStorage` under `persistKey`. The list
453
+ is grouped the way the table paints — pinned left, loose, pinned right — and
454
+ a move stays inside its group, so what you drag is where it lands. A column
455
+ whose header is a node rather than text is listed by position: “#3”.
456
+ `columnManager={false}` drops the button for a layout the host fixes or
457
+ drives itself; the layout props keep working without it.
453
458
  - **Expandable rows** and **inline cell editing** on double click, with
454
459
  optimistic saving and a rollback on failure.
455
460
  - **States** — skeletons on the first load, a thin progress line when refetching
package/dist/index.cjs CHANGED
@@ -160,8 +160,8 @@ var ArrowUpIcon = icon(/* @__PURE__ */ jsxRuntime.jsx("path", { d: "M12 19V5m-7
160
160
  var ArrowDownIcon = icon(/* @__PURE__ */ jsxRuntime.jsx("path", { d: "M12 5v14m7-7-7 7-7-7" }));
161
161
  var SortIcon = icon(
162
162
  /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
163
- /* @__PURE__ */ jsxRuntime.jsx("path", { d: "m7 15 3 3 3-3", opacity: "0.9" }),
164
- /* @__PURE__ */ jsxRuntime.jsx("path", { d: "m7 9 3-3 3 3", opacity: "0.9" })
163
+ /* @__PURE__ */ jsxRuntime.jsx("path", { d: "m8 10 4-4 4 4" }),
164
+ /* @__PURE__ */ jsxRuntime.jsx("path", { d: "m8 14 4 4 4-4" })
165
165
  ] })
166
166
  );
167
167
  var FilterIcon = icon(/* @__PURE__ */ jsxRuntime.jsx("path", { d: "M4 5h16l-6.5 7.5V19l-3 2v-8.5L4 5Z" }));
@@ -181,7 +181,13 @@ var GripIcon = icon(
181
181
  /* @__PURE__ */ jsxRuntime.jsx("circle", { cx: "15", cy: "17", r: "1.4", fill: "currentColor" })
182
182
  ] })
183
183
  );
184
- var PinIcon = icon(/* @__PURE__ */ jsxRuntime.jsx("path", { d: "M15 3 21 9l-4 1-4 4-1 5-6-6 5-1 4-4 1-4Z" }));
184
+ var PinIcon = icon(
185
+ /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
186
+ /* @__PURE__ */ jsxRuntime.jsx("path", { d: "M9 4h6v5l3 4v2H6v-2l3-4V4Z" }),
187
+ /* @__PURE__ */ jsxRuntime.jsx("path", { d: "M8 4h8" }),
188
+ /* @__PURE__ */ jsxRuntime.jsx("path", { d: "M12 15v5" })
189
+ ] })
190
+ );
185
191
  var EyeIcon = icon(
186
192
  /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
187
193
  /* @__PURE__ */ jsxRuntime.jsx("path", { d: "M2 12s3.5-7 10-7 10 7 10 7-3.5 7-10 7-10-7-10-7Z" }),
@@ -2104,26 +2110,53 @@ function FilterChip({
2104
2110
  /* @__PURE__ */ jsxRuntime.jsx("button", { type: "button", onClick: onClear, "aria-label": clearLabel, className: "mz-focusable", children: "\xD7" })
2105
2111
  ] });
2106
2112
  }
2113
+ function nameOf(column, declaredIndex) {
2114
+ if (column.label?.trim()) return column.label;
2115
+ if (typeof column.header === "string" && column.header.trim()) return column.header;
2116
+ return `#${declaredIndex + 1}`;
2117
+ }
2107
2118
  function ColumnManager({
2108
2119
  columns,
2109
2120
  layout,
2110
2121
  onToggleHidden,
2111
2122
  onSetPinned,
2112
- onMove,
2113
2123
  onMoveTo,
2114
2124
  onReset,
2115
2125
  labels: labelsProp
2116
2126
  }) {
2117
2127
  const labels = resolveLabels(labelsProp);
2118
2128
  const [dragging, setDragging] = React39__namespace.useState(null);
2119
- const byId = React39__namespace.useMemo(() => new Map(columns.map((c) => [c.id, c])), [columns]);
2120
- const ordered = layout.order.map((id) => byId.get(id)).filter((c) => Boolean(c));
2129
+ const [dropTarget, setDropTarget] = React39__namespace.useState(null);
2130
+ const entries = React39__namespace.useMemo(() => {
2131
+ const byId = new Map(columns.map((c, index) => [c.id, { column: c, declaredIndex: index }]));
2132
+ const ordered = layout.order.map((id) => byId.get(id)).filter((e) => Boolean(e));
2133
+ const side = (id) => layout.pinned[id];
2134
+ const groups = ["left", void 0, "right"];
2135
+ return groups.flatMap((group) => {
2136
+ const inGroup = ordered.filter((e) => side(e.column.id) === group);
2137
+ return inGroup.map((entry, indexInGroup) => ({
2138
+ ...entry,
2139
+ side: group,
2140
+ indexInGroup,
2141
+ groupSize: inGroup.length,
2142
+ previous: inGroup[indexInGroup - 1]?.column.id,
2143
+ next: inGroup[indexInGroup + 1]?.column.id,
2144
+ name: nameOf(entry.column, entry.declaredIndex)
2145
+ }));
2146
+ });
2147
+ }, [columns, layout]);
2148
+ const sideOf = (id) => layout.pinned[id];
2149
+ const canDrop = (targetId) => Boolean(dragging) && dragging !== targetId && sideOf(dragging) === sideOf(targetId);
2150
+ const endDrag = () => {
2151
+ setDragging(null);
2152
+ setDropTarget(null);
2153
+ };
2121
2154
  const hiddenCount = layout.hidden.length;
2122
2155
  return /* @__PURE__ */ jsxRuntime.jsxs(Popover, { children: [
2123
2156
  /* @__PURE__ */ jsxRuntime.jsx(PopoverTrigger, { asChild: true, children: /* @__PURE__ */ jsxRuntime.jsxs(Button, { variant: "secondary", size: "sm", children: [
2124
2157
  /* @__PURE__ */ jsxRuntime.jsx(ColumnsIcon, {}),
2125
2158
  labels.columns,
2126
- hiddenCount > 0 ? /* @__PURE__ */ jsxRuntime.jsx("span", { className: "mz-dt__count", children: ordered.length - hiddenCount }) : null
2159
+ hiddenCount > 0 ? /* @__PURE__ */ jsxRuntime.jsx("span", { className: "mz-dt__count", children: entries.length - hiddenCount }) : null
2127
2160
  ] }) }),
2128
2161
  /* @__PURE__ */ jsxRuntime.jsxs(PopoverContent, { align: "end", className: "mz-dt__columns", children: [
2129
2162
  /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "mz-dt__columns-head", children: [
@@ -2131,35 +2164,60 @@ function ColumnManager({
2131
2164
  /* @__PURE__ */ jsxRuntime.jsx(Button, { variant: "link", size: "xs", onClick: onReset, children: labels.reset })
2132
2165
  ] }),
2133
2166
  /* @__PURE__ */ jsxRuntime.jsx(Separator, {}),
2134
- /* @__PURE__ */ jsxRuntime.jsx("ul", { className: "mz-dt__columns-list", children: ordered.map((column, index) => {
2167
+ /* @__PURE__ */ jsxRuntime.jsx("ul", { className: "mz-dt__columns-list", children: entries.map((entry) => {
2168
+ const column = entry.column;
2135
2169
  const hidden = layout.hidden.includes(column.id);
2136
- const pinned = layout.pinned[column.id];
2137
- const label = column.label ?? (typeof column.header === "string" ? column.header : column.id);
2170
+ const pinned = entry.side;
2171
+ const name = entry.name;
2172
+ const pinTitle = pinned === "left" ? labels.pinnedLeft : pinned === "right" ? labels.pinnedRight : labels.notPinned;
2138
2173
  return /* @__PURE__ */ jsxRuntime.jsxs(
2139
2174
  "li",
2140
2175
  {
2141
2176
  className: "mz-dt__columns-item",
2142
2177
  "data-dragging": dragging === column.id || void 0,
2178
+ "data-drop": dropTarget === column.id || void 0,
2179
+ "data-pinned": pinned,
2143
2180
  draggable: true,
2144
- onDragStart: () => setDragging(column.id),
2145
- onDragEnd: () => setDragging(null),
2146
- onDragOver: (event) => event.preventDefault(),
2147
- onDrop: () => {
2148
- if (dragging && dragging !== column.id) onMoveTo(dragging, column.id);
2149
- setDragging(null);
2181
+ onDragStart: (event) => {
2182
+ if (event.target.closest(".mz-dt__columns-controls")) {
2183
+ event.preventDefault();
2184
+ return;
2185
+ }
2186
+ setDragging(column.id);
2187
+ event.dataTransfer.effectAllowed = "move";
2188
+ try {
2189
+ event.dataTransfer.setData("text/plain", column.id);
2190
+ } catch {
2191
+ }
2192
+ },
2193
+ onDragEnd: endDrag,
2194
+ onDragOver: (event) => {
2195
+ if (!canDrop(column.id)) {
2196
+ event.dataTransfer.dropEffect = "none";
2197
+ return;
2198
+ }
2199
+ event.preventDefault();
2200
+ event.dataTransfer.dropEffect = "move";
2201
+ setDropTarget(column.id);
2202
+ },
2203
+ onDragLeave: () => setDropTarget((c) => c === column.id ? null : c),
2204
+ onDrop: (event) => {
2205
+ event.preventDefault();
2206
+ if (canDrop(column.id)) onMoveTo(dragging, column.id);
2207
+ endDrag();
2150
2208
  },
2151
2209
  children: [
2152
2210
  /* @__PURE__ */ jsxRuntime.jsx("span", { className: "mz-dt__columns-grip", "aria-hidden": "true", children: /* @__PURE__ */ jsxRuntime.jsx(GripIcon, {}) }),
2153
- /* @__PURE__ */ jsxRuntime.jsx("span", { className: "mz-dt__columns-label", children: label }),
2154
- /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "mz-dt__columns-controls", children: [
2211
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "mz-dt__columns-label", children: name }),
2212
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "mz-dt__columns-controls", draggable: false, children: [
2155
2213
  /* @__PURE__ */ jsxRuntime.jsx(
2156
2214
  "button",
2157
2215
  {
2158
2216
  type: "button",
2159
2217
  className: "mz-dt__icon-btn mz-focusable",
2160
- disabled: index === 0,
2161
- onClick: () => onMove(column.id, -1),
2162
- "aria-label": labels.moveUp(label),
2218
+ disabled: !entry.previous,
2219
+ onClick: () => entry.previous && onMoveTo(column.id, entry.previous),
2220
+ "aria-label": labels.moveUp(name),
2163
2221
  children: "\u2191"
2164
2222
  }
2165
2223
  ),
@@ -2168,9 +2226,9 @@ function ColumnManager({
2168
2226
  {
2169
2227
  type: "button",
2170
2228
  className: "mz-dt__icon-btn mz-focusable",
2171
- disabled: index === ordered.length - 1,
2172
- onClick: () => onMove(column.id, 1),
2173
- "aria-label": labels.moveDown(label),
2229
+ disabled: !entry.next,
2230
+ onClick: () => entry.next && onMoveTo(column.id, entry.next),
2231
+ "aria-label": labels.moveDown(name),
2174
2232
  children: "\u2193"
2175
2233
  }
2176
2234
  ),
@@ -2178,14 +2236,12 @@ function ColumnManager({
2178
2236
  "button",
2179
2237
  {
2180
2238
  type: "button",
2181
- className: "mz-dt__icon-btn mz-focusable",
2239
+ className: "mz-dt__icon-btn mz-dt__pin mz-focusable",
2182
2240
  "data-active": pinned ? true : void 0,
2241
+ "data-pinned": pinned,
2183
2242
  onClick: () => onSetPinned(column.id, pinned === "left" ? "right" : pinned === "right" ? void 0 : "left"),
2184
- "aria-label": labels.pinning(
2185
- label,
2186
- pinned === "left" ? labels.pinnedLeft : pinned === "right" ? labels.pinnedRight : labels.notPinned
2187
- ),
2188
- title: pinned === "left" ? labels.pinnedLeft : pinned === "right" ? labels.pinnedRight : labels.notPinned,
2243
+ "aria-label": labels.pinning(name, pinTitle),
2244
+ title: pinTitle,
2189
2245
  children: /* @__PURE__ */ jsxRuntime.jsx(PinIcon, {})
2190
2246
  }
2191
2247
  ),
@@ -2196,7 +2252,7 @@ function ColumnManager({
2196
2252
  className: "mz-dt__icon-btn mz-focusable",
2197
2253
  disabled: column.hideable === false,
2198
2254
  onClick: () => onToggleHidden(column.id),
2199
- "aria-label": hidden ? labels.show(label) : labels.hide(label),
2255
+ "aria-label": hidden ? labels.show(name) : labels.hide(name),
2200
2256
  children: hidden ? /* @__PURE__ */ jsxRuntime.jsx(EyeOffIcon, {}) : /* @__PURE__ */ jsxRuntime.jsx(EyeIcon, {})
2201
2257
  }
2202
2258
  )
@@ -2649,6 +2705,7 @@ function DataTable({
2649
2705
  onLayoutChange,
2650
2706
  persistKey = null,
2651
2707
  toolbar,
2708
+ columnManager = true,
2652
2709
  autoFit = true,
2653
2710
  density = "normal",
2654
2711
  stickyHeader = true,
@@ -2677,7 +2734,6 @@ function DataTable({
2677
2734
  setWidth,
2678
2735
  toggleHidden,
2679
2736
  setPinned,
2680
- move,
2681
2737
  moveTo,
2682
2738
  reset,
2683
2739
  fitTo
@@ -2909,22 +2965,25 @@ function DataTable({
2909
2965
  className: cn("mz-dt", className),
2910
2966
  style: widthVars,
2911
2967
  children: [
2912
- (toolbar || chips.length > 0 || columns.some((c) => c.hideable !== false)) && /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "mz-dt__toolbar", children: [
2913
- /* @__PURE__ */ jsxRuntime.jsx("div", { className: "mz-dt__toolbar-main", children: toolbar }),
2914
- /* @__PURE__ */ jsxRuntime.jsx("div", { className: "mz-dt__toolbar-side", children: /* @__PURE__ */ jsxRuntime.jsx(
2915
- ColumnManager,
2916
- {
2917
- columns,
2918
- layout,
2919
- labels: labelsProp,
2920
- onToggleHidden: toggleHidden,
2921
- onSetPinned: setPinned,
2922
- onMove: move,
2923
- onMoveTo: moveTo,
2924
- onReset: reset
2925
- }
2926
- ) })
2927
- ] }),
2968
+ (() => {
2969
+ const showManager = columnManager && columns.some((c) => c.hideable !== false);
2970
+ if (!toolbar && chips.length === 0 && !showManager) return null;
2971
+ return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "mz-dt__toolbar", children: [
2972
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "mz-dt__toolbar-main", children: toolbar }),
2973
+ showManager && /* @__PURE__ */ jsxRuntime.jsx("div", { className: "mz-dt__toolbar-side", children: /* @__PURE__ */ jsxRuntime.jsx(
2974
+ ColumnManager,
2975
+ {
2976
+ columns,
2977
+ layout,
2978
+ labels: labelsProp,
2979
+ onToggleHidden: toggleHidden,
2980
+ onSetPinned: setPinned,
2981
+ onMoveTo: moveTo,
2982
+ onReset: reset
2983
+ }
2984
+ ) })
2985
+ ] });
2986
+ })(),
2928
2987
  chips.length > 0 && /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "mz-dt__chips", children: [
2929
2988
  chips.map(([id, value]) => /* @__PURE__ */ jsxRuntime.jsx(
2930
2989
  FilterChip,