@dxos/react-ui-table 0.4.7-next.f4b92be → 0.4.8-main.00e6f19

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/src/helpers.tsx CHANGED
@@ -17,6 +17,7 @@ import { formatDistanceToNow } from 'date-fns/formatDistanceToNow';
17
17
  import React, { useEffect, useRef, useState } from 'react';
18
18
 
19
19
  import { type PublicKey } from '@dxos/keys';
20
+ import { log } from '@dxos/log';
20
21
  import { type ClassNameValue, Input, Tooltip } from '@dxos/react-ui';
21
22
  import { getSize, mx } from '@dxos/react-ui-theme';
22
23
 
@@ -94,8 +95,11 @@ const ComboboxBuilderCell = <TData extends RowData>(cellContext: CellContext<TDa
94
95
  };
95
96
 
96
97
  const StringBuilderCell = <TData extends RowData>(cellContext: CellContext<TData, string>) => {
97
- const inputRef = useRef<HTMLInputElement>(null);
98
- const { onUpdate } = cellContext.column.columnDef.meta as ColumnMeta<TData, string>;
98
+ const ref = useRef<HTMLInputElement>(null);
99
+ const { findPrevFocusable } = useFocusFinders();
100
+
101
+ const { onUpdate, cell } = cellContext.column.columnDef.meta as ColumnMeta<TData, string>;
102
+
99
103
  // https://tanstack.com/table/v8/docs/examples/react/editable-data
100
104
  const initialValue = cellContext.getValue();
101
105
  const [value, setValue] = useState(() => {
@@ -108,16 +112,14 @@ const StringBuilderCell = <TData extends RowData>(cellContext: CellContext<TData
108
112
  });
109
113
 
110
114
  const handleSave = () => {
111
- if (value === initialValue) {
112
- return;
113
- }
115
+ ref.current && document.activeElement === ref.current && findPrevFocusable(ref.current)?.focus();
114
116
 
115
- onUpdate?.(cellContext.row.original, cellContext.column.id, value);
117
+ if (value !== initialValue) {
118
+ onUpdate?.(cellContext.row.original, cellContext.column.id, value);
119
+ }
116
120
  };
117
121
 
118
- const handleCancel = () => {
119
- setValue(initialValue);
120
- };
122
+ const handleCancel = () => setValue(initialValue);
121
123
 
122
124
  // Check if first input column of last row.
123
125
  const rows = cellContext.table.getRowModel().flatRows;
@@ -128,12 +130,12 @@ const StringBuilderCell = <TData extends RowData>(cellContext: CellContext<TData
128
130
  return (
129
131
  <Input.Root>
130
132
  <Input.TextInput
131
- ref={inputRef}
133
+ ref={ref}
132
134
  variant='subdued'
133
135
  placeholder={placeholder ? 'Add row...' : undefined}
134
- classNames={['is-full', textPadding]}
136
+ classNames={['is-full', textPadding, cell?.classNames]}
135
137
  value={value ?? ''}
136
- onBlur={() => handleSave()}
138
+ onBlur={handleSave}
137
139
  onChange={(event) => setValue(event.target.value)}
138
140
  onKeyDown={(event) => (event.key === 'Enter' && handleSave()) || (event.key === 'Escape' && handleCancel())}
139
141
  />
@@ -163,17 +165,20 @@ const NumberBuilderCell = <TData extends RowData>(cellContext: CellContext<TData
163
165
  (!document.activeElement || document.activeElement !== ref.current) && setText(displayNumber(value, digits));
164
166
  }, [digits, value]);
165
167
 
166
- const handleEdit = () => {
167
- if (onUpdate) {
168
- setText(value !== undefined ? String(value) : '');
169
- }
170
- };
168
+ const handleEdit = () => setText(value !== undefined ? String(value) : '');
171
169
 
172
170
  // TODO(burdon): Property is encoded as float (e.g., 6.1 => 6.099)
173
171
  const handleSave = () => {
174
172
  const nextValue = parseNumber(text);
175
- onUpdate?.(cellContext.row.original, cellContext.column.id, isNaN(nextValue) ? undefined : nextValue);
176
- setText(displayNumber(nextValue, digits));
173
+
174
+ if (!isNaN(nextValue)) {
175
+ onUpdate?.(cellContext.row.original, cellContext.column.id, nextValue);
176
+ setText(displayNumber(nextValue, digits));
177
+ } else {
178
+ // Reset the text to display the original value without updating the model.
179
+ setText(displayNumber(value, digits));
180
+ }
181
+
177
182
  // Shift focus only if input is focused on save (e.g. on `Enter`).
178
183
  ref.current && document.activeElement === ref.current && findPrevFocusable(ref.current)?.focus();
179
184
  };
@@ -209,20 +214,23 @@ const RowSelectorBuilderCell = <TData extends RowData>(cellContext: CellContext<
209
214
  const checked = row.getCanSelect()
210
215
  ? row.getIsSelected()
211
216
  : row.getCanSelectSubRows() && (row.getIsSomeSelected() ? 'indeterminate' : row.getIsAllSubRowsSelected());
217
+
212
218
  return (
213
- <Input.Root>
214
- <Input.Checkbox
215
- size={4}
216
- classNames={['mli-auto', cell?.classNames]}
217
- checked={checked}
218
- onCheckedChange={(event) => {
219
- if (row.getCanSelect()) {
220
- row.getToggleSelectedHandler()(event);
221
- }
222
- }}
223
- disabled={!(row.getCanSelect() || row.getCanSelectSubRows())}
224
- />
225
- </Input.Root>
219
+ <div className='flex justify-center w-full h-full' role='presentation'>
220
+ <Input.Root>
221
+ <Input.Checkbox
222
+ size={4}
223
+ classNames={[cell?.classNames]}
224
+ checked={checked}
225
+ onCheckedChange={(event) => {
226
+ if (row.getCanSelect()) {
227
+ row.getToggleSelectedHandler()(event);
228
+ }
229
+ }}
230
+ disabled={!(row.getCanSelect() || row.getCanSelectSubRows())}
231
+ />
232
+ </Input.Root>
233
+ </div>
226
234
  );
227
235
  };
228
236
 
@@ -359,7 +367,7 @@ export class ColumnBuilder<TData extends RowData> {
359
367
 
360
368
  return <div className={mx(textPadding, classNames)}>{str}</div>;
361
369
  } catch (err) {
362
- console.log(value);
370
+ log.info('formatError', { value });
363
371
  return null;
364
372
  }
365
373
  },
@@ -421,21 +429,22 @@ export class ColumnBuilder<TData extends RowData> {
421
429
  return {
422
430
  id,
423
431
  size: 32,
424
- minSize: 32,
425
- maxSize: 32,
432
+ enableResizing: false,
426
433
  meta: { onUpdate, cell: { classNames } },
427
434
  header: ({ table }) => {
428
435
  const { rowsSelectable } = useTableContext('HELPER_SELECT_ROW_HEADER_CELL');
429
436
  const checked = table.getIsSomeRowsSelected() ? 'indeterminate' : table.getIsAllRowsSelected();
430
437
  return rowsSelectable === 'multi' ? (
431
- <Input.Root>
432
- <Input.Checkbox
433
- size={4}
434
- classNames={['mli-auto', classNames]}
435
- checked={checked}
436
- onCheckedChange={() => table.toggleAllRowsSelected()}
437
- />
438
- </Input.Root>
438
+ <div className='flex justify-center w-full h-full' role='presentation'>
439
+ <Input.Root>
440
+ <Input.Checkbox
441
+ size={4}
442
+ classNames={['mli-auto', classNames]}
443
+ checked={checked}
444
+ onCheckedChange={() => table.toggleAllRowsSelected()}
445
+ />
446
+ </Input.Root>
447
+ </div>
439
448
  ) : null;
440
449
  },
441
450
  cell: RowSelectorBuilderCell,
package/src/theme.ts CHANGED
@@ -23,7 +23,8 @@ export const flushPadding = 'pli-0 plb-0';
23
23
  export const textPadding = 'pli-2 plb-0.5';
24
24
  export const headPadding = 'pli-2 plb-1.5';
25
25
 
26
- export const gridCellFocusRing = 'focus:z-[11] focus:outline outline-2 outline-primary-500 dark:outline-primary-400';
26
+ export const gridCellFocusRing =
27
+ 'focus-within:z-[11] focus-within:outline outline-2 outline-primary-500 dark:outline-primary-400';
27
28
 
28
29
  //
29
30
  // table
@@ -89,6 +90,7 @@ export const tbodyTr: ComponentFunction<TbodyTrStyleProps> = ({ canBeCurrent },
89
90
 
90
91
  export const tdRoot: ComponentFunction<TbodyStyleProps> = ({ border, isGrid }, ...etc) =>
91
92
  mx('relative', flushPadding, border && 'border', border && groupBorder, isGrid && gridCellFocusRing, ...etc);
93
+
92
94
  export const tdContent: ComponentFunction<CellContext<any, any>> = (_props, ...etc) => mx(...etc);
93
95
 
94
96
  //