@morze/ui 0.2.6 → 0.2.8

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
@@ -21,6 +21,15 @@ active navigation item. The label itself stays flat — the embossed
21
21
  `text-shadow` is off (`--mz-convex-text-shadow: none`), as on the landing,
22
22
  because on a 34px control it only made the text shout.
23
23
 
24
+ The surfaces that other content passes behind are **glass**: menus, popovers,
25
+ dialogs, the sheet, the sidebar rail and a sticky table header are a
26
+ translucent cut of the same surface ramp over a backdrop blur
27
+ (`--mz-glass*`), so a menu frosts the page under it and a pinned header
28
+ frosts the rows scrolling past. Controls stay convex and opaque — glass is
29
+ for what things float over, not for what you press. With
30
+ `prefers-reduced-transparency`, or in an engine without `backdrop-filter`,
31
+ the glass falls back to the opaque ramp.
32
+
24
33
  ## Install
25
34
 
26
35
  ```bash
@@ -226,7 +235,9 @@ Safari 16.2+, the same baseline as the rest of the kit.
226
235
  Everything is driven by custom properties; override them after importing the
227
236
  styles. The main groups: surfaces (`--mz-bg`, `--mz-surface`, `--mz-elevated`),
228
237
  borders, text, tones, the convex recipe (`--mz-convex-*`, `--mz-face*`,
229
- `--mz-well*`), geometry (`--mz-radius*`), type (`--mz-font-*`, `--mz-label-*`),
238
+ `--mz-well*`), the glass layer (`--mz-glass`, `--mz-glass-chrome`,
239
+ `--mz-glass-well`, `--mz-glass-filter`, `--mz-glass-sheen`),
240
+ geometry (`--mz-radius*`), type (`--mz-font-*`, `--mz-label-*`),
230
241
  motion and states (`--mz-ease`, `--mz-duration`, `--mz-hover-scale`,
231
242
  `--mz-press-scale`, `--mz-hover-mix`, `--mz-press-mix`), focus (`--mz-ring-*`).
232
243
 
@@ -449,7 +460,12 @@ What it does:
449
460
  and the floating bar can escalate to "all N matching" (in that mode a bulk
450
461
  action must travel with the query, not with a list of ids).
451
462
  - **Columns** — visibility, order (drag and drop plus arrows for the keyboard)
452
- and pinning; all of it saved to `localStorage` under `persistKey`.
463
+ and pinning; all of it saved to `localStorage` under `persistKey`. The list
464
+ is grouped the way the table paints — pinned left, loose, pinned right — and
465
+ a move stays inside its group, so what you drag is where it lands. A column
466
+ whose header is a node rather than text is listed by position: “#3”.
467
+ `columnManager={false}` drops the button for a layout the host fixes or
468
+ drives itself; the layout props keep working without it.
453
469
  - **Expandable rows** and **inline cell editing** on double click, with
454
470
  optimistic saving and a rollback on failure.
455
471
  - **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,