@rufous/ui 0.2.87 → 0.2.89

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/dist/main.cjs CHANGED
@@ -4308,6 +4308,7 @@ function DataGrid({
4308
4308
  onCellDoubleClick
4309
4309
  }) {
4310
4310
  const sxClass = useSx(sx);
4311
+ const [editingCell, setEditingCell] = (0, import_react23.useState)(null);
4311
4312
  const [columnOverrides, setColumnOverrides] = (0, import_react23.useState)({});
4312
4313
  const resolvedColumns = (0, import_react23.useMemo)(() => {
4313
4314
  return initialColumnsProp.map((col) => {
@@ -4438,8 +4439,8 @@ function DataGrid({
4438
4439
  );
4439
4440
  const evalFilter = (f) => {
4440
4441
  if (!f.value && f.operator !== "is empty" && f.operator !== "is not empty") return true;
4441
- const rawVal = String(item[f.column]);
4442
4442
  const col = resolvedColumns.find((c) => String(c.field) === f.column || String(c.key) === f.column);
4443
+ const rawVal = String(item[f.column]);
4443
4444
  if (col?.type === "number") {
4444
4445
  const itemNum = Number(rawVal);
4445
4446
  const filterNum = Number(f.value);
@@ -4465,23 +4466,30 @@ function DataGrid({
4465
4466
  }
4466
4467
  }
4467
4468
  if (col?.type === "date") {
4469
+ const raw = item[f.column];
4470
+ const resolvedDate = col.valueGetter ? col.valueGetter({ value: raw, row: item, field: f.column }) : raw;
4471
+ const isEmpty = resolvedDate == null || resolvedDate === "" || resolvedDate === "undefined" || resolvedDate === "null";
4472
+ if (f.operator === "is empty") return isEmpty;
4473
+ if (f.operator === "is not empty") return !isEmpty;
4474
+ if (isEmpty) return false;
4475
+ const itemTs = new Date(resolvedDate);
4476
+ itemTs.setHours(0, 0, 0, 0);
4477
+ const filterTs = new Date(f.value);
4478
+ filterTs.setHours(0, 0, 0, 0);
4479
+ if (isNaN(itemTs.getTime()) || isNaN(filterTs.getTime())) return false;
4468
4480
  switch (f.operator) {
4469
4481
  case "is":
4470
- return rawVal === f.value;
4482
+ return itemTs.getTime() === filterTs.getTime();
4471
4483
  case "is not":
4472
- return rawVal !== f.value;
4484
+ return itemTs.getTime() !== filterTs.getTime();
4473
4485
  case "is after":
4474
- return rawVal > f.value;
4486
+ return itemTs.getTime() > filterTs.getTime();
4475
4487
  case "is on or after":
4476
- return rawVal >= f.value;
4488
+ return itemTs.getTime() >= filterTs.getTime();
4477
4489
  case "is before":
4478
- return rawVal < f.value;
4490
+ return itemTs.getTime() < filterTs.getTime();
4479
4491
  case "is on or before":
4480
- return rawVal <= f.value;
4481
- case "is empty":
4482
- return !rawVal;
4483
- case "is not empty":
4484
- return !!rawVal;
4492
+ return itemTs.getTime() <= filterTs.getTime();
4485
4493
  default:
4486
4494
  return true;
4487
4495
  }
@@ -4694,14 +4702,46 @@ function DataGrid({
4694
4702
  "td",
4695
4703
  {
4696
4704
  key: `${item.id}-${colField}`,
4697
- className: `dg-td${col.pinned === "left" ? " pinned-left" : col.pinned === "right" ? " pinned-right" : ""} ${col.cellClassName || ""}`,
4705
+ className: `dg-td${col.pinned === "left" ? " pinned-left" : col.pinned === "right" ? " pinned-right" : ""}${col.editable ? " dg-td--editable" : ""} ${col.cellClassName || ""}`,
4698
4706
  style: { width, minWidth: width, maxWidth: width, left: leftOffset, right: rightOffset, flex: col.flex },
4699
- onDoubleClick: () => onCellDoubleClick?.({ row: item, field: colField, value: item[col.field || ""] })
4707
+ onDoubleClick: () => onCellDoubleClick?.({ row: item, field: colField, value: item[col.field || ""] }),
4708
+ onClick: col.editable ? () => {
4709
+ const field = String(col.field);
4710
+ const rawValue = item[col.field || ""];
4711
+ const value = col.valueGetter ? col.valueGetter({ value: rawValue, row: item, field }) : rawValue;
4712
+ setEditingCell({ rowId: item.id, field, value });
4713
+ } : void 0
4700
4714
  },
4701
4715
  (() => {
4702
4716
  const field = String(col.field);
4703
4717
  const rawValue = item[col.field || ""];
4704
4718
  let value = col.valueGetter ? col.valueGetter({ value: rawValue, row: item, field }) : rawValue;
4719
+ if (col.editable && editingCell?.rowId === item.id && editingCell?.field === field) {
4720
+ const inputType = col.type === "number" ? "number" : col.type === "date" ? "date" : "text";
4721
+ const commit = (finalValue) => {
4722
+ setEditingCell(null);
4723
+ col.onEnter?.({ value: finalValue, row: item, field });
4724
+ };
4725
+ return /* @__PURE__ */ import_react23.default.createElement(
4726
+ "input",
4727
+ {
4728
+ className: "dg-cell-editor",
4729
+ type: inputType,
4730
+ autoFocus: true,
4731
+ defaultValue: editingCell.value ?? "",
4732
+ onClick: (e) => e.stopPropagation(),
4733
+ onKeyDown: (e) => {
4734
+ if (e.key === "Enter") commit(e.target.value);
4735
+ if (e.key === "Escape") setEditingCell(null);
4736
+ },
4737
+ onBlur: (e) => {
4738
+ const finalValue = e.target.value;
4739
+ setEditingCell(null);
4740
+ col.onBlur?.({ value: finalValue, row: item, field });
4741
+ }
4742
+ }
4743
+ );
4744
+ }
4705
4745
  const formattedValue = col.valueFormatter ? col.valueFormatter({ value, row: item, field }) : value;
4706
4746
  if (col.renderCell) {
4707
4747
  return col.renderCell({ value, row: item, field });
@@ -12341,7 +12381,11 @@ var RufousTextEditor = ({
12341
12381
  };
12342
12382
  var RufousTextContent = ({ content, className, style, sx }) => {
12343
12383
  const sxClass = useSx(sx);
12344
- const transformedContent = (0, import_react59.useMemo)(() => transformLegacyTodos(content || ""), [content]);
12384
+ let transformedContent = content || "";
12385
+ try {
12386
+ transformedContent = transformLegacyTodos(transformedContent);
12387
+ } catch {
12388
+ }
12345
12389
  return /* @__PURE__ */ import_react59.default.createElement(
12346
12390
  "div",
12347
12391
  {
package/dist/main.css CHANGED
@@ -531,6 +531,25 @@
531
531
  white-space: nowrap;
532
532
  background: inherit;
533
533
  }
534
+ .dg-td--editable {
535
+ cursor: pointer;
536
+ }
537
+ .dg-td--editable:hover {
538
+ outline: 1px dashed var(--border-color);
539
+ outline-offset: -2px;
540
+ }
541
+ .dg-cell-editor {
542
+ width: 100%;
543
+ padding: 4px 6px;
544
+ font: inherit;
545
+ font-size: 0.875rem;
546
+ color: var(--text-color);
547
+ background: var(--surface-color);
548
+ border: 1.5px solid var(--primary-color, #f15b24);
549
+ border-radius: 4px;
550
+ outline: none;
551
+ box-sizing: border-box;
552
+ }
534
553
  .dg-td.pinned-left {
535
554
  position: sticky;
536
555
  left: 0;
package/dist/main.d.cts CHANGED
@@ -796,6 +796,16 @@ interface Column<T> {
796
796
  type?: 'string' | 'number' | 'date' | 'boolean' | 'actions' | 'status';
797
797
  statusOptions?: string[];
798
798
  editable?: boolean;
799
+ onEnter?: (params: {
800
+ value: any;
801
+ row: T;
802
+ field: string;
803
+ }) => void;
804
+ onBlur?: (params: {
805
+ value: any;
806
+ row: T;
807
+ field: string;
808
+ }) => void;
799
809
  headerClassName?: string;
800
810
  cellClassName?: string;
801
811
  hideable?: boolean;
package/dist/main.d.ts CHANGED
@@ -796,6 +796,16 @@ interface Column<T> {
796
796
  type?: 'string' | 'number' | 'date' | 'boolean' | 'actions' | 'status';
797
797
  statusOptions?: string[];
798
798
  editable?: boolean;
799
+ onEnter?: (params: {
800
+ value: any;
801
+ row: T;
802
+ field: string;
803
+ }) => void;
804
+ onBlur?: (params: {
805
+ value: any;
806
+ row: T;
807
+ field: string;
808
+ }) => void;
799
809
  headerClassName?: string;
800
810
  cellClassName?: string;
801
811
  hideable?: boolean;
package/dist/main.js CHANGED
@@ -4178,6 +4178,7 @@ function DataGrid({
4178
4178
  onCellDoubleClick
4179
4179
  }) {
4180
4180
  const sxClass = useSx(sx);
4181
+ const [editingCell, setEditingCell] = useState9(null);
4181
4182
  const [columnOverrides, setColumnOverrides] = useState9({});
4182
4183
  const resolvedColumns = useMemo2(() => {
4183
4184
  return initialColumnsProp.map((col) => {
@@ -4308,8 +4309,8 @@ function DataGrid({
4308
4309
  );
4309
4310
  const evalFilter = (f) => {
4310
4311
  if (!f.value && f.operator !== "is empty" && f.operator !== "is not empty") return true;
4311
- const rawVal = String(item[f.column]);
4312
4312
  const col = resolvedColumns.find((c) => String(c.field) === f.column || String(c.key) === f.column);
4313
+ const rawVal = String(item[f.column]);
4313
4314
  if (col?.type === "number") {
4314
4315
  const itemNum = Number(rawVal);
4315
4316
  const filterNum = Number(f.value);
@@ -4335,23 +4336,30 @@ function DataGrid({
4335
4336
  }
4336
4337
  }
4337
4338
  if (col?.type === "date") {
4339
+ const raw = item[f.column];
4340
+ const resolvedDate = col.valueGetter ? col.valueGetter({ value: raw, row: item, field: f.column }) : raw;
4341
+ const isEmpty = resolvedDate == null || resolvedDate === "" || resolvedDate === "undefined" || resolvedDate === "null";
4342
+ if (f.operator === "is empty") return isEmpty;
4343
+ if (f.operator === "is not empty") return !isEmpty;
4344
+ if (isEmpty) return false;
4345
+ const itemTs = new Date(resolvedDate);
4346
+ itemTs.setHours(0, 0, 0, 0);
4347
+ const filterTs = new Date(f.value);
4348
+ filterTs.setHours(0, 0, 0, 0);
4349
+ if (isNaN(itemTs.getTime()) || isNaN(filterTs.getTime())) return false;
4338
4350
  switch (f.operator) {
4339
4351
  case "is":
4340
- return rawVal === f.value;
4352
+ return itemTs.getTime() === filterTs.getTime();
4341
4353
  case "is not":
4342
- return rawVal !== f.value;
4354
+ return itemTs.getTime() !== filterTs.getTime();
4343
4355
  case "is after":
4344
- return rawVal > f.value;
4356
+ return itemTs.getTime() > filterTs.getTime();
4345
4357
  case "is on or after":
4346
- return rawVal >= f.value;
4358
+ return itemTs.getTime() >= filterTs.getTime();
4347
4359
  case "is before":
4348
- return rawVal < f.value;
4360
+ return itemTs.getTime() < filterTs.getTime();
4349
4361
  case "is on or before":
4350
- return rawVal <= f.value;
4351
- case "is empty":
4352
- return !rawVal;
4353
- case "is not empty":
4354
- return !!rawVal;
4362
+ return itemTs.getTime() <= filterTs.getTime();
4355
4363
  default:
4356
4364
  return true;
4357
4365
  }
@@ -4564,14 +4572,46 @@ function DataGrid({
4564
4572
  "td",
4565
4573
  {
4566
4574
  key: `${item.id}-${colField}`,
4567
- className: `dg-td${col.pinned === "left" ? " pinned-left" : col.pinned === "right" ? " pinned-right" : ""} ${col.cellClassName || ""}`,
4575
+ className: `dg-td${col.pinned === "left" ? " pinned-left" : col.pinned === "right" ? " pinned-right" : ""}${col.editable ? " dg-td--editable" : ""} ${col.cellClassName || ""}`,
4568
4576
  style: { width, minWidth: width, maxWidth: width, left: leftOffset, right: rightOffset, flex: col.flex },
4569
- onDoubleClick: () => onCellDoubleClick?.({ row: item, field: colField, value: item[col.field || ""] })
4577
+ onDoubleClick: () => onCellDoubleClick?.({ row: item, field: colField, value: item[col.field || ""] }),
4578
+ onClick: col.editable ? () => {
4579
+ const field = String(col.field);
4580
+ const rawValue = item[col.field || ""];
4581
+ const value = col.valueGetter ? col.valueGetter({ value: rawValue, row: item, field }) : rawValue;
4582
+ setEditingCell({ rowId: item.id, field, value });
4583
+ } : void 0
4570
4584
  },
4571
4585
  (() => {
4572
4586
  const field = String(col.field);
4573
4587
  const rawValue = item[col.field || ""];
4574
4588
  let value = col.valueGetter ? col.valueGetter({ value: rawValue, row: item, field }) : rawValue;
4589
+ if (col.editable && editingCell?.rowId === item.id && editingCell?.field === field) {
4590
+ const inputType = col.type === "number" ? "number" : col.type === "date" ? "date" : "text";
4591
+ const commit = (finalValue) => {
4592
+ setEditingCell(null);
4593
+ col.onEnter?.({ value: finalValue, row: item, field });
4594
+ };
4595
+ return /* @__PURE__ */ React75.createElement(
4596
+ "input",
4597
+ {
4598
+ className: "dg-cell-editor",
4599
+ type: inputType,
4600
+ autoFocus: true,
4601
+ defaultValue: editingCell.value ?? "",
4602
+ onClick: (e) => e.stopPropagation(),
4603
+ onKeyDown: (e) => {
4604
+ if (e.key === "Enter") commit(e.target.value);
4605
+ if (e.key === "Escape") setEditingCell(null);
4606
+ },
4607
+ onBlur: (e) => {
4608
+ const finalValue = e.target.value;
4609
+ setEditingCell(null);
4610
+ col.onBlur?.({ value: finalValue, row: item, field });
4611
+ }
4612
+ }
4613
+ );
4614
+ }
4575
4615
  const formattedValue = col.valueFormatter ? col.valueFormatter({ value, row: item, field }) : value;
4576
4616
  if (col.renderCell) {
4577
4617
  return col.renderCell({ value, row: item, field });
@@ -12275,7 +12315,11 @@ var RufousTextEditor = ({
12275
12315
  };
12276
12316
  var RufousTextContent = ({ content, className, style, sx }) => {
12277
12317
  const sxClass = useSx(sx);
12278
- const transformedContent = useMemo4(() => transformLegacyTodos(content || ""), [content]);
12318
+ let transformedContent = content || "";
12319
+ try {
12320
+ transformedContent = transformLegacyTodos(transformedContent);
12321
+ } catch {
12322
+ }
12279
12323
  return /* @__PURE__ */ React116.createElement(
12280
12324
  "div",
12281
12325
  {
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@rufous/ui",
3
3
  "private": false,
4
- "version": "0.2.87",
4
+ "version": "0.2.89",
5
5
  "type": "module",
6
6
  "description": "Experimental: A lightweight React UI component library (Beta)",
7
7
  "style": "./dist/main.css",