@milktop/react-ui 0.2.4 → 0.2.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.
@@ -23,7 +23,8 @@
23
23
  * - `selectable`: a checkbox per row and a select-all; `selected`,
24
24
  * `defaultSelected`: the selected rows' keys; `onSelectedChange`. Shift-click
25
25
  * a row's checkbox to tick (or clear) the rows between it and the last one
26
- * clicked
26
+ * clicked. Once a row is ticked, clicking a row ticks (or clears) it too,
27
+ * Shift a run, rather than calling `onRowClick`
27
28
  * - `loading`: skeleton rows while there are none yet (`loadingRows`, 5),
28
29
  * else dims the rows
29
30
  * - `emptyText`, or `empty` (markup), for no rows
@@ -31,7 +32,8 @@
31
32
  * - `label`: a caption for assistive tech
32
33
  * - `size`: 'sm', 'md' (default) or 'lg' (roomier rows)
33
34
  * - `flush`: no border or rounding, to sit edge to edge in a card
34
- * - `onRowClick`: called with the row when a row is clicked (outside its controls)
35
+ * - `onRowClick`: called with the row when a row is clicked (outside its
36
+ * controls), unless rows are ticked
35
37
  *
36
38
  * Or write the <table> yourself as its content, for the look alone (no
37
39
  * sorting, selection or loading states); `data-align` on cells works too.
@@ -24,7 +24,8 @@ import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-run
24
24
  * - `selectable`: a checkbox per row and a select-all; `selected`,
25
25
  * `defaultSelected`: the selected rows' keys; `onSelectedChange`. Shift-click
26
26
  * a row's checkbox to tick (or clear) the rows between it and the last one
27
- * clicked
27
+ * clicked. Once a row is ticked, clicking a row ticks (or clears) it too,
28
+ * Shift a run, rather than calling `onRowClick`
28
29
  * - `loading`: skeleton rows while there are none yet (`loadingRows`, 5),
29
30
  * else dims the rows
30
31
  * - `emptyText`, or `empty` (markup), for no rows
@@ -32,7 +33,8 @@ import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-run
32
33
  * - `label`: a caption for assistive tech
33
34
  * - `size`: 'sm', 'md' (default) or 'lg' (roomier rows)
34
35
  * - `flush`: no border or rounding, to sit edge to edge in a card
35
- * - `onRowClick`: called with the row when a row is clicked (outside its controls)
36
+ * - `onRowClick`: called with the row when a row is clicked (outside its
37
+ * controls), unless rows are ticked
36
38
  *
37
39
  * Or write the <table> yourself as its content, for the look alone (no
38
40
  * sorting, selection or loading states); `data-align` on cells works too.
@@ -97,6 +99,8 @@ export function Table({ columns = [], rows = [], rowKey = 'id', selectable = fal
97
99
  const isSelected = (row) => selected.includes(keyOf(row));
98
100
  const selectedCount = rows.filter(isSelected).length;
99
101
  const allState = selectedCount === 0 ? false : selectedCount === rows.length ? true : 'indeterminate';
102
+ // Once a row is ticked, a click on a row ticks it rather than opening it.
103
+ const selecting = selectable && selected.length > 0;
100
104
  // Change events don't carry the Shift key, so it's noted on the way in;
101
105
  // Shift+mousedown would also select the text between.
102
106
  const shift = useRef(false);
@@ -104,7 +108,7 @@ export function Table({ columns = [], rows = [], rowKey = 'id', selectable = fal
104
108
  function noteShift(e) {
105
109
  const event = e.nativeEvent;
106
110
  shift.current = event.shiftKey;
107
- if (event.shiftKey && e.type === 'mousedown' && e.target.closest('[data-part=select-cell]'))
111
+ if (event.shiftKey && e.type === 'mousedown' && (selecting || e.target.closest('[data-part=select-cell]')))
108
112
  e.preventDefault();
109
113
  }
110
114
  function toggleRow(row, on) {
@@ -131,10 +135,13 @@ export function Table({ columns = [], rows = [], rowKey = 'id', selectable = fal
131
135
  const control = e.target.closest('a, button, input, label, select, textarea, [data-scope]:not([data-scope=table])');
132
136
  if (control && e.currentTarget.contains(control))
133
137
  return;
134
- onRowClick?.(row);
138
+ if (selecting)
139
+ toggleRow(row, !isSelected(row));
140
+ else
141
+ onRowClick?.(row);
135
142
  }
136
143
  const columnCount = columns.length + (selectable ? 1 : 0);
137
- return (_jsx("div", { ...rest, ...part('root'), className: cx(className, classes?.root), "data-size": size, "data-flush": flush || undefined, "data-loading": (loading && rows.length > 0) || undefined, children: _jsx("div", { ...part('scroll'), "data-sticky": maxHeight ? '' : undefined, style: maxHeight ? { maxHeight } : undefined, children: !columns.length ? children : (_jsxs("table", { ...part('table'), "aria-busy": loading, children: [label && _jsx("caption", { ...part('caption'), children: label }), _jsx("thead", { children: _jsxs("tr", { children: [selectable && (_jsx("th", { ...part('select-cell'), scope: "col", children: _jsx(Checkbox, { label: t.table.selectAll, labelHidden: true, disabled: !rows.length, checked: allState, onCheckedChange: (on) => toggleAll(on) }) })), columns.map((column) => (_jsx("th", { scope: "col", "data-align": column.align ?? 'start', "aria-sort": ariaSort(column), style: column.width ? { width: column.width } : undefined, children: column.sortable
144
+ return (_jsx("div", { ...rest, ...part('root'), className: cx(className, classes?.root), "data-size": size, "data-flush": flush || undefined, "data-selecting": selecting || undefined, "data-loading": (loading && rows.length > 0) || undefined, children: _jsx("div", { ...part('scroll'), "data-sticky": maxHeight ? '' : undefined, style: maxHeight ? { maxHeight } : undefined, children: !columns.length ? children : (_jsxs("table", { ...part('table'), "aria-busy": loading, children: [label && _jsx("caption", { ...part('caption'), children: label }), _jsx("thead", { children: _jsxs("tr", { children: [selectable && (_jsx("th", { ...part('select-cell'), scope: "col", children: _jsx(Checkbox, { label: t.table.selectAll, labelHidden: true, disabled: !rows.length, checked: allState, onCheckedChange: (on) => toggleAll(on) }) })), columns.map((column) => (_jsx("th", { scope: "col", "data-align": column.align ?? 'start', "aria-sort": ariaSort(column), style: column.width ? { width: column.width } : undefined, children: column.sortable
138
145
  ? _jsxs("button", { ...part('sort'), type: "button", "data-dir": sortDir(column) ?? undefined, onClick: () => toggleSort(column), children: [_jsx("span", { children: column.label }), _jsx("span", { ...part('sort-icon'), children: _jsx("iconify-icon", { icon: sortDir(column) === 'asc' ? 'lucide:chevron-up'
139
146
  : sortDir(column) === 'desc' ? 'lucide:chevron-down' : 'lucide:chevrons-up-down' }) })] })
140
147
  : column.label }, column.key)))] }) }), _jsx("tbody", { onPointerDownCapture: noteShift, onMouseDownCapture: noteShift, onKeyDownCapture: noteShift, children: loading && !rows.length
@@ -23,6 +23,8 @@
23
23
  & tbody tr:last-child td { border-bottom: none; }
24
24
  & tbody tr:hover { background: color-mix(in srgb, var(--ui-hover) 60%, transparent); }
25
25
  & tbody tr[data-selected] { background: color-mix(in srgb, var(--ui-accent-soft) 45%, transparent); }
26
+ /* While rows are ticked, a click on a row ticks it. */
27
+ [data-selecting] > & tbody tr { cursor: pointer; }
26
28
  /* Outer cells line up with a card's padding. */
27
29
  [data-flush] > & :is(th, td):first-child { padding-left: 1.25rem; }
28
30
  [data-flush] > & :is(th, td):last-child { padding-right: 1.25rem; } }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@milktop/react-ui",
3
- "version": "0.2.4",
3
+ "version": "0.2.5",
4
4
  "description": "React components on Ark UI (Zag state machines), with imba-ui's API and design",
5
5
  "license": "MIT",
6
6
  "author": "André Goldstein",