react-open-source-grid 1.6.4 → 1.6.6

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.
@@ -341,6 +341,7 @@ __export(index_exports, {
341
341
  ColumnFilters: () => ColumnFilters,
342
342
  CurrencyCell: () => CurrencyCell,
343
343
  DataGrid: () => DataGrid,
344
+ DateEditor: () => DateEditor,
344
345
  DensityToggle: () => DensityToggle,
345
346
  ExportMenu: () => ExportMenu,
346
347
  FacetedSearch: () => FacetedSearch,
@@ -353,11 +354,16 @@ __export(index_exports, {
353
354
  LayoutPersistenceManager: () => LayoutPersistenceManager,
354
355
  LayoutPresetsManager: () => LayoutPresetsManager,
355
356
  LocalStorageAdapter: () => LocalStorageAdapter,
357
+ MarkdownEditor: () => MarkdownEditor,
356
358
  MarketDataEngine: () => MarketDataEngine,
357
359
  MarketDataGrid: () => MarketDataGrid,
360
+ MultiSelectEditor: () => MultiSelectEditor,
361
+ NumericEditor: () => NumericEditor,
362
+ PivotToolbar: () => PivotToolbar,
358
363
  PriorityIndicator: () => PriorityIndicator,
359
364
  ProgressBar: () => ProgressBar,
360
365
  Rating: () => Rating,
366
+ RichSelectEditor: () => RichSelectEditor,
361
367
  ServerAdapter: () => ServerAdapter,
362
368
  ServerSideDataSource: () => ServerSideDataSource,
363
369
  StatusChip: () => StatusChip,
@@ -367,6 +373,7 @@ __export(index_exports, {
367
373
  VirtualScroller: () => VirtualScroller,
368
374
  WebSocketMockFeed: () => WebSocketMockFeed,
369
375
  alpineTheme: () => alpineTheme,
376
+ buildPivot: () => buildPivot,
370
377
  buildTreeFromFlat: () => buildTreeFromFlat,
371
378
  collapseAllNodes: () => collapseAllNodes,
372
379
  countTreeNodes: () => countTreeNodes,
@@ -376,12 +383,17 @@ __export(index_exports, {
376
383
  createMockWebSocket: () => createMockWebSocket,
377
384
  createPreset: () => createPreset,
378
385
  darkTheme: () => darkTheme,
386
+ debounce: () => debounce2,
379
387
  densityConfigs: () => densityConfigs,
388
+ downloadCSV: () => downloadCSV,
380
389
  expandAllNodes: () => expandAllNodes,
390
+ exportPivotToCSV: () => exportPivotToCSV,
381
391
  exportToCSV: () => exportToCSV,
382
392
  exportToXLSX: () => exportToXLSX,
393
+ filterOptions: () => filterOptions,
383
394
  filterTree: () => filterTree,
384
395
  flattenTree: () => flattenTree,
396
+ formatNumber: () => formatNumber,
385
397
  generateDensityCSS: () => generateDensityCSS,
386
398
  generateFilename: () => generateFilename,
387
399
  generatePresetId: () => generatePresetId,
@@ -399,12 +411,17 @@ __export(index_exports, {
399
411
  isTreeNode: () => isTreeNode,
400
412
  loadDensityMode: () => loadDensityMode,
401
413
  materialTheme: () => materialTheme,
414
+ parseFormattedNumber: () => parseFormattedNumber,
402
415
  quartzTheme: () => quartzTheme,
403
416
  saveDensityMode: () => saveDensityMode,
404
417
  themes: () => themes,
405
418
  toggleNodeExpansion: () => toggleNodeExpansion,
406
419
  useDensityMode: () => useDensityMode,
407
- useMarketData: () => useMarketData
420
+ useEditorAutoFocus: () => useEditorAutoFocus,
421
+ useEditorClickOutside: () => useEditorClickOutside,
422
+ useEditorKeyboardNavigation: () => useEditorKeyboardNavigation,
423
+ useMarketData: () => useMarketData,
424
+ usePopupPosition: () => usePopupPosition
408
425
  });
409
426
  module.exports = __toCommonJS(index_exports);
410
427
 
@@ -2755,7 +2772,16 @@ var GridBody = ({
2755
2772
  onKeyDown: (e) => handleKeyDown(e, rowIndex, columnIndex),
2756
2773
  tabIndex: isCellFocused ? 0 : -1
2757
2774
  },
2758
- isEditing ? /* @__PURE__ */ import_react6.default.createElement(
2775
+ isEditing ? column.editor ? column.editor({
2776
+ value: editState.value,
2777
+ row,
2778
+ column,
2779
+ onChange: handleEditChange,
2780
+ onCommit: handleEditComplete,
2781
+ onCancel: () => dispatch({ type: "END_EDIT" }),
2782
+ autoFocus: true,
2783
+ ...column.editorParams
2784
+ }) : /* @__PURE__ */ import_react6.default.createElement(
2759
2785
  "input",
2760
2786
  {
2761
2787
  ref: editInputRef,
@@ -5426,7 +5452,7 @@ var LayoutPresetsManager = ({
5426
5452
  setLoading(false);
5427
5453
  }
5428
5454
  };
5429
- const formatDate = (timestamp) => {
5455
+ const formatDate2 = (timestamp) => {
5430
5456
  return new Date(timestamp).toLocaleString();
5431
5457
  };
5432
5458
  return /* @__PURE__ */ import_react14.default.createElement("div", { className: "relative inline-block" }, /* @__PURE__ */ import_react14.default.createElement(
@@ -5540,7 +5566,7 @@ var LayoutPresetsManager = ({
5540
5566
  if (buttons) buttons.style.opacity = "0";
5541
5567
  }
5542
5568
  },
5543
- /* @__PURE__ */ import_react14.default.createElement("div", { style: { display: "flex", alignItems: "flex-start", justifyContent: "space-between" } }, /* @__PURE__ */ import_react14.default.createElement("div", { style: { flex: 1, minWidth: 0 } }, /* @__PURE__ */ import_react14.default.createElement("h4", { style: { fontSize: "14px", fontWeight: "500", color: "#111827", overflow: "hidden", textOverflow: "ellipsis", whiteSpace: "nowrap" } }, preset.name), preset.description && /* @__PURE__ */ import_react14.default.createElement("p", { style: { fontSize: "12px", color: "#6b7280", marginTop: "4px", overflow: "hidden", textOverflow: "ellipsis", whiteSpace: "nowrap" } }, preset.description), /* @__PURE__ */ import_react14.default.createElement("p", { style: { fontSize: "12px", color: "#9ca3af", marginTop: "4px" } }, "Updated: ", formatDate(preset.updatedAt))), /* @__PURE__ */ import_react14.default.createElement("div", { className: "preset-actions", style: { display: "flex", gap: "4px", marginLeft: "8px", opacity: 0, transition: "opacity 0.2s" } }, /* @__PURE__ */ import_react14.default.createElement(
5569
+ /* @__PURE__ */ import_react14.default.createElement("div", { style: { display: "flex", alignItems: "flex-start", justifyContent: "space-between" } }, /* @__PURE__ */ import_react14.default.createElement("div", { style: { flex: 1, minWidth: 0 } }, /* @__PURE__ */ import_react14.default.createElement("h4", { style: { fontSize: "14px", fontWeight: "500", color: "#111827", overflow: "hidden", textOverflow: "ellipsis", whiteSpace: "nowrap" } }, preset.name), preset.description && /* @__PURE__ */ import_react14.default.createElement("p", { style: { fontSize: "12px", color: "#6b7280", marginTop: "4px", overflow: "hidden", textOverflow: "ellipsis", whiteSpace: "nowrap" } }, preset.description), /* @__PURE__ */ import_react14.default.createElement("p", { style: { fontSize: "12px", color: "#9ca3af", marginTop: "4px" } }, "Updated: ", formatDate2(preset.updatedAt))), /* @__PURE__ */ import_react14.default.createElement("div", { className: "preset-actions", style: { display: "flex", gap: "4px", marginLeft: "8px", opacity: 0, transition: "opacity 0.2s" } }, /* @__PURE__ */ import_react14.default.createElement(
5544
5570
  "button",
5545
5571
  {
5546
5572
  onClick: (e) => handleUpdatePreset(preset, e),
@@ -8445,6 +8471,195 @@ var GridApiImpl = class {
8445
8471
  }
8446
8472
  };
8447
8473
 
8474
+ // src/components/DataGrid/pivotEngine.ts
8475
+ var AGGREGATORS = {
8476
+ sum: (values) => values.reduce((acc, val) => acc + val, 0),
8477
+ count: (values) => values.length,
8478
+ avg: (values) => values.length > 0 ? values.reduce((acc, val) => acc + val, 0) / values.length : 0,
8479
+ min: (values) => values.length > 0 ? Math.min(...values) : 0,
8480
+ max: (values) => values.length > 0 ? Math.max(...values) : 0
8481
+ };
8482
+ function getUniqueValues(data, column) {
8483
+ const uniqueSet = /* @__PURE__ */ new Set();
8484
+ data.forEach((row) => {
8485
+ const value = row[column];
8486
+ if (value !== null && value !== void 0) {
8487
+ uniqueSet.add(String(value));
8488
+ }
8489
+ });
8490
+ return Array.from(uniqueSet).sort();
8491
+ }
8492
+ function getAggregatorFn(aggregator) {
8493
+ if (typeof aggregator === "function") {
8494
+ return aggregator;
8495
+ }
8496
+ return AGGREGATORS[aggregator] || AGGREGATORS.sum;
8497
+ }
8498
+ function toNumber(value) {
8499
+ if (typeof value === "number") return value;
8500
+ if (typeof value === "string") {
8501
+ const num = parseFloat(value);
8502
+ return isNaN(num) ? 0 : num;
8503
+ }
8504
+ return 0;
8505
+ }
8506
+ function buildPivot(data, config) {
8507
+ const {
8508
+ pivotColumn,
8509
+ valueColumn,
8510
+ rowGroupColumn,
8511
+ aggregator,
8512
+ showTotals = false,
8513
+ showGrandTotal = false
8514
+ } = config;
8515
+ if (!data || data.length === 0) {
8516
+ return {
8517
+ columns: [],
8518
+ rows: [],
8519
+ pivotValues: []
8520
+ };
8521
+ }
8522
+ const pivotValues = getUniqueValues(data, pivotColumn);
8523
+ const rowGroupValues = getUniqueValues(data, rowGroupColumn);
8524
+ const aggregatorFn = getAggregatorFn(aggregator);
8525
+ const groupedData = /* @__PURE__ */ new Map();
8526
+ rowGroupValues.forEach((rowValue) => {
8527
+ const pivotMap = /* @__PURE__ */ new Map();
8528
+ pivotValues.forEach((pivotValue) => {
8529
+ pivotMap.set(pivotValue, []);
8530
+ });
8531
+ groupedData.set(rowValue, pivotMap);
8532
+ });
8533
+ data.forEach((row) => {
8534
+ const rowValue = String(row[rowGroupColumn] ?? "");
8535
+ const pivotValue = String(row[pivotColumn] ?? "");
8536
+ const value = toNumber(row[valueColumn]);
8537
+ if (groupedData.has(rowValue)) {
8538
+ const pivotMap = groupedData.get(rowValue);
8539
+ if (pivotMap.has(pivotValue)) {
8540
+ pivotMap.get(pivotValue).push(value);
8541
+ }
8542
+ }
8543
+ });
8544
+ const columns = [
8545
+ {
8546
+ field: rowGroupColumn,
8547
+ headerName: formatHeaderName(rowGroupColumn),
8548
+ width: 180,
8549
+ sortable: true,
8550
+ filterable: true,
8551
+ isPivotColumn: false
8552
+ }
8553
+ ];
8554
+ pivotValues.forEach((pivotValue) => {
8555
+ columns.push({
8556
+ field: pivotValue,
8557
+ headerName: pivotValue,
8558
+ width: 120,
8559
+ sortable: true,
8560
+ filterable: true,
8561
+ isPivotColumn: true
8562
+ });
8563
+ });
8564
+ if (showGrandTotal) {
8565
+ columns.push({
8566
+ field: "__grandTotal",
8567
+ headerName: "Grand Total",
8568
+ width: 120,
8569
+ sortable: true,
8570
+ filterable: false,
8571
+ isTotalColumn: true
8572
+ });
8573
+ }
8574
+ const rows = [];
8575
+ rowGroupValues.forEach((rowValue) => {
8576
+ const pivotMap = groupedData.get(rowValue);
8577
+ const row = {
8578
+ [rowGroupColumn]: rowValue,
8579
+ __id: rowValue
8580
+ // Add unique ID for grid
8581
+ };
8582
+ let grandTotal = 0;
8583
+ pivotValues.forEach((pivotValue) => {
8584
+ const values = pivotMap.get(pivotValue);
8585
+ const aggregatedValue = aggregatorFn(values);
8586
+ row[pivotValue] = aggregatedValue;
8587
+ grandTotal += aggregatedValue;
8588
+ });
8589
+ if (showGrandTotal) {
8590
+ row["__grandTotal"] = grandTotal;
8591
+ }
8592
+ rows.push(row);
8593
+ });
8594
+ let totalsRow;
8595
+ if (showTotals) {
8596
+ totalsRow = {
8597
+ [rowGroupColumn]: "Total",
8598
+ __id: "__totals",
8599
+ __isTotal: true
8600
+ };
8601
+ let overallGrandTotal = 0;
8602
+ pivotValues.forEach((pivotValue) => {
8603
+ const allValues = [];
8604
+ groupedData.forEach((pivotMap) => {
8605
+ const values = pivotMap.get(pivotValue);
8606
+ allValues.push(...values);
8607
+ });
8608
+ const total = aggregatorFn(allValues);
8609
+ totalsRow[pivotValue] = total;
8610
+ overallGrandTotal += total;
8611
+ });
8612
+ if (showGrandTotal) {
8613
+ totalsRow["__grandTotal"] = overallGrandTotal;
8614
+ }
8615
+ }
8616
+ return {
8617
+ columns,
8618
+ rows,
8619
+ pivotValues,
8620
+ totalsRow
8621
+ };
8622
+ }
8623
+ function formatHeaderName(field) {
8624
+ return field.split(/(?=[A-Z])|_|-/).map((word) => word.charAt(0).toUpperCase() + word.slice(1).toLowerCase()).join(" ");
8625
+ }
8626
+ function exportPivotToCSV(pivotResult) {
8627
+ const { columns, rows, totalsRow } = pivotResult;
8628
+ const headers = columns.map((col) => col.headerName).join(",");
8629
+ const dataRows = rows.map((row) => {
8630
+ return columns.map((col) => {
8631
+ const value = row[col.field];
8632
+ if (typeof value === "string" && value.includes(",")) {
8633
+ return `"${value}"`;
8634
+ }
8635
+ return value ?? "";
8636
+ }).join(",");
8637
+ });
8638
+ if (totalsRow) {
8639
+ const totalRow = columns.map((col) => {
8640
+ const value = totalsRow[col.field];
8641
+ if (typeof value === "string" && value.includes(",")) {
8642
+ return `"${value}"`;
8643
+ }
8644
+ return value ?? "";
8645
+ }).join(",");
8646
+ dataRows.push(totalRow);
8647
+ }
8648
+ return [headers, ...dataRows].join("\n");
8649
+ }
8650
+ function downloadCSV(csvContent, filename = "pivot-table.csv") {
8651
+ const blob = new Blob([csvContent], { type: "text/csv;charset=utf-8;" });
8652
+ const link = document.createElement("a");
8653
+ const url = URL.createObjectURL(blob);
8654
+ link.setAttribute("href", url);
8655
+ link.setAttribute("download", filename);
8656
+ link.style.visibility = "hidden";
8657
+ document.body.appendChild(link);
8658
+ link.click();
8659
+ document.body.removeChild(link);
8660
+ URL.revokeObjectURL(url);
8661
+ }
8662
+
8448
8663
  // src/components/DataGrid/DataGrid.tsx
8449
8664
  var DataGrid = (0, import_react23.forwardRef)(({
8450
8665
  columns,
@@ -8459,6 +8674,7 @@ var DataGrid = (0, import_react23.forwardRef)(({
8459
8674
  rowPinConfig,
8460
8675
  contextMenuConfig,
8461
8676
  tooltipConfig,
8677
+ pivotConfig,
8462
8678
  tableId,
8463
8679
  theme: _theme = "quartz",
8464
8680
  densityMode: _densityMode = "normal",
@@ -8479,6 +8695,42 @@ var DataGrid = (0, import_react23.forwardRef)(({
8479
8695
  );
8480
8696
  const [internalRows, setInternalRows] = (0, import_react23.useState)(null);
8481
8697
  const activeRows = internalRows !== null ? internalRows : rows;
8698
+ const { pivotedData, effectiveColumns } = (0, import_react23.useMemo)(() => {
8699
+ if (!pivotConfig) {
8700
+ return { pivotedData: activeRows, effectiveColumns: columns };
8701
+ }
8702
+ const pivotResult = buildPivot(activeRows, pivotConfig);
8703
+ console.log("Pivot Result:", {
8704
+ columnsCount: pivotResult.columns.length,
8705
+ columns: pivotResult.columns.map((c) => c.field),
8706
+ rowsCount: pivotResult.rows.length,
8707
+ sampleRow: pivotResult.rows[0]
8708
+ });
8709
+ const pivotColumns = pivotResult.columns.map((col) => ({
8710
+ field: col.field,
8711
+ headerName: col.headerName,
8712
+ width: col.width || 120,
8713
+ sortable: col.sortable !== false,
8714
+ filterable: col.filterable !== false,
8715
+ editable: false,
8716
+ renderCell: col.isTotalColumn || col.isPivotColumn ? (row) => {
8717
+ const value = row[col.field];
8718
+ if (typeof value === "number") {
8719
+ return /* @__PURE__ */ import_react23.default.createElement("span", { style: {
8720
+ fontWeight: col.isTotalColumn ? "700" : "600",
8721
+ color: col.isTotalColumn ? "#0f766e" : "#475569"
8722
+ } }, value.toLocaleString(void 0, { minimumFractionDigits: 2, maximumFractionDigits: 2 }));
8723
+ }
8724
+ return value;
8725
+ } : void 0
8726
+ }));
8727
+ const allRows = pivotResult.totalsRow ? [...pivotResult.rows, pivotResult.totalsRow] : pivotResult.rows;
8728
+ const rowsWithId = allRows.map((row, index) => ({
8729
+ ...row,
8730
+ id: row.__id || row.id || `pivot-row-${index}`
8731
+ }));
8732
+ return { pivotedData: rowsWithId, effectiveColumns: pivotColumns };
8733
+ }, [activeRows, columns, pivotConfig]);
8482
8734
  const rowsRef = (0, import_react23.useRef)(rows);
8483
8735
  (0, import_react23.useEffect)(() => {
8484
8736
  if (rows !== rowsRef.current) {
@@ -8581,8 +8833,8 @@ var DataGrid = (0, import_react23.forwardRef)(({
8581
8833
  gridApiRef.current = new GridApiImpl(
8582
8834
  state,
8583
8835
  dispatch,
8584
- columns,
8585
- activeRows,
8836
+ effectiveColumns,
8837
+ pivotedData,
8586
8838
  containerRef,
8587
8839
  persistenceManager,
8588
8840
  setInternalRows
@@ -8592,24 +8844,24 @@ var DataGrid = (0, import_react23.forwardRef)(({
8592
8844
  (0, import_react23.useEffect)(() => {
8593
8845
  if (gridApiRef.current && !gridApiRef.current.isDestroyed()) {
8594
8846
  gridApiRef.current.updateState(state);
8595
- gridApiRef.current.updateData(columns, activeRows);
8847
+ gridApiRef.current.updateData(effectiveColumns, pivotedData);
8596
8848
  gridApiRef.current.updateCallbacks(setInternalRows);
8597
8849
  }
8598
- }, [state, columns, activeRows, setInternalRows]);
8850
+ }, [state, effectiveColumns, pivotedData, setInternalRows]);
8599
8851
  (0, import_react23.useImperativeHandle)(ref, () => {
8600
8852
  if (!gridApiRef.current || gridApiRef.current.isDestroyed()) {
8601
8853
  gridApiRef.current = new GridApiImpl(
8602
8854
  state,
8603
8855
  dispatch,
8604
- columns,
8605
- activeRows,
8856
+ effectiveColumns,
8857
+ pivotedData,
8606
8858
  containerRef,
8607
8859
  persistenceManager,
8608
8860
  setInternalRows
8609
8861
  );
8610
8862
  }
8611
8863
  return gridApiRef.current;
8612
- }, [state, columns, activeRows, persistenceManager]);
8864
+ }, [state, effectiveColumns, pivotedData, persistenceManager]);
8613
8865
  const onGridReadyCalledRef = (0, import_react23.useRef)(false);
8614
8866
  const onGridReadyCallbackRef = (0, import_react23.useRef)(onGridReady);
8615
8867
  (0, import_react23.useEffect)(() => {
@@ -8690,9 +8942,11 @@ var DataGrid = (0, import_react23.forwardRef)(({
8690
8942
  ...middleColumns,
8691
8943
  ...pinnedRightFields
8692
8944
  ];
8945
+ console.log("Display column order:", displayColumnOrder, "from state.columnOrder:", state.columnOrder);
8693
8946
  (0, import_react23.useEffect)(() => {
8694
- dispatch({ type: "RESET_COLUMNS", payload: columns });
8695
- }, [columns]);
8947
+ console.log("Dispatching RESET_COLUMNS with", effectiveColumns.length, "columns:", effectiveColumns.map((c) => c.field));
8948
+ dispatch({ type: "RESET_COLUMNS", payload: effectiveColumns });
8949
+ }, [effectiveColumns]);
8696
8950
  (0, import_react23.useEffect)(() => {
8697
8951
  if (onSelectionChange) {
8698
8952
  onSelectionChange(Array.from(state.selection.selectedRows));
@@ -8708,17 +8962,17 @@ var DataGrid = (0, import_react23.forwardRef)(({
8708
8962
  }, [state.pinnedRowsTop, state.pinnedRowsBottom]);
8709
8963
  (0, import_react23.useEffect)(() => {
8710
8964
  if (state.sortConfig.field) {
8711
- const column = columns.find((c) => c.field === state.sortConfig.field);
8965
+ const column = effectiveColumns.find((c) => c.field === state.sortConfig.field);
8712
8966
  if (column) {
8713
8967
  announceSorting(column.headerName, state.sortConfig.direction);
8714
8968
  }
8715
8969
  }
8716
- }, [state.sortConfig.field, state.sortConfig.direction]);
8970
+ }, [state.sortConfig.field, state.sortConfig.direction, effectiveColumns]);
8717
8971
  const sortedRows = (0, import_react23.useMemo)(() => {
8718
8972
  if (!state.sortConfig.field || !state.sortConfig.direction) {
8719
- return activeRows;
8973
+ return pivotedData;
8720
8974
  }
8721
- const sorted = [...activeRows].sort((a, b) => {
8975
+ const sorted = [...pivotedData].sort((a, b) => {
8722
8976
  const aValue = a[state.sortConfig.field];
8723
8977
  const bValue = b[state.sortConfig.field];
8724
8978
  if (aValue == null && bValue == null) return 0;
@@ -8735,7 +8989,7 @@ var DataGrid = (0, import_react23.forwardRef)(({
8735
8989
  sorted.reverse();
8736
8990
  }
8737
8991
  return sorted;
8738
- }, [activeRows, state.sortConfig]);
8992
+ }, [pivotedData, state.sortConfig]);
8739
8993
  const filteredRows = (0, import_react23.useMemo)(() => {
8740
8994
  if (!hasActiveFilters(state.filterConfig)) {
8741
8995
  return sortedRows;
@@ -8881,7 +9135,7 @@ var DataGrid = (0, import_react23.forwardRef)(({
8881
9135
  /* @__PURE__ */ import_react23.default.createElement("div", { style: { position: "relative", display: "flex", alignItems: "center", justifyContent: "space-between", paddingLeft: "16px", paddingRight: "16px", paddingTop: "10px", paddingBottom: "10px", backgroundColor: "var(--grid-bg-alt)", borderBottom: "var(--grid-border-width, 1px) solid var(--grid-border)", zIndex: 30 } }, /* @__PURE__ */ import_react23.default.createElement("div", { style: { position: "relative", display: "flex", alignItems: "center", gap: "8px" } }, /* @__PURE__ */ import_react23.default.createElement(
8882
9136
  ColumnChooser,
8883
9137
  {
8884
- columns,
9138
+ columns: effectiveColumns,
8885
9139
  columnOrder: state.columnOrder,
8886
9140
  hiddenColumns: state.hiddenColumns,
8887
9141
  onToggleVisibility: (field) => dispatch({ type: "TOGGLE_COLUMN_VISIBILITY", payload: field }),
@@ -8891,7 +9145,7 @@ var DataGrid = (0, import_react23.forwardRef)(({
8891
9145
  ), /* @__PURE__ */ import_react23.default.createElement(
8892
9146
  ExportMenu,
8893
9147
  {
8894
- columns,
9148
+ columns: effectiveColumns,
8895
9149
  fullDataset: rows,
8896
9150
  filteredData: filteredRows.filter((r) => !("isGroup" in r)),
8897
9151
  selectedRows: state.selection.selectedRows,
@@ -8909,7 +9163,7 @@ var DataGrid = (0, import_react23.forwardRef)(({
8909
9163
  /* @__PURE__ */ import_react23.default.createElement(
8910
9164
  GroupByPanel,
8911
9165
  {
8912
- columns,
9166
+ columns: effectiveColumns,
8913
9167
  groupBy: state.groupBy,
8914
9168
  dispatch
8915
9169
  }
@@ -8917,7 +9171,7 @@ var DataGrid = (0, import_react23.forwardRef)(({
8917
9171
  /* @__PURE__ */ import_react23.default.createElement("div", { role: "rowgroup", style: { position: "sticky", top: 0, zIndex: 20, width: "100%" } }, /* @__PURE__ */ import_react23.default.createElement(
8918
9172
  GridHeader,
8919
9173
  {
8920
- columns,
9174
+ columns: effectiveColumns,
8921
9175
  columnOrder: state.columnOrder,
8922
9176
  displayColumnOrder,
8923
9177
  columnWidths: state.columnWidths,
@@ -8936,7 +9190,7 @@ var DataGrid = (0, import_react23.forwardRef)(({
8936
9190
  ), /* @__PURE__ */ import_react23.default.createElement(
8937
9191
  ColumnFilters,
8938
9192
  {
8939
- columns,
9193
+ columns: effectiveColumns,
8940
9194
  displayColumnOrder,
8941
9195
  columnWidths: state.columnWidths,
8942
9196
  filterConfig: state.filterConfig,
@@ -8949,7 +9203,7 @@ var DataGrid = (0, import_react23.forwardRef)(({
8949
9203
  /* @__PURE__ */ import_react23.default.createElement(
8950
9204
  GridBody,
8951
9205
  {
8952
- columns,
9206
+ columns: effectiveColumns,
8953
9207
  rows: (virtualScrollConfig == null ? void 0 : virtualScrollConfig.enabled) ? unpinnedRows : paginatedRows,
8954
9208
  pinnedRowsTop: pinnedRowsTopData,
8955
9209
  pinnedRowsBottom: pinnedRowsBottomData,
@@ -8989,7 +9243,7 @@ var DataGrid = (0, import_react23.forwardRef)(({
8989
9243
  (footerConfig == null ? void 0 : footerConfig.show) && footerConfig.aggregates && /* @__PURE__ */ import_react23.default.createElement(
8990
9244
  GridFooter,
8991
9245
  {
8992
- columns,
9246
+ columns: effectiveColumns,
8993
9247
  displayColumnOrder,
8994
9248
  columnWidths: state.columnWidths,
8995
9249
  aggregates: globalAggregates,
@@ -12157,6 +12411,1532 @@ function createMockFeed(config) {
12157
12411
  createConnection: () => createMockWebSocket(feed)
12158
12412
  };
12159
12413
  }
12414
+
12415
+ // src/components/DataGrid/PivotToolbar.tsx
12416
+ var import_react33 = __toESM(require("react"), 1);
12417
+ var AGGREGATOR_OPTIONS = [
12418
+ { value: "sum", label: "Sum" },
12419
+ { value: "avg", label: "Average" },
12420
+ { value: "count", label: "Count" },
12421
+ { value: "min", label: "Minimum" },
12422
+ { value: "max", label: "Maximum" }
12423
+ ];
12424
+ var PivotToolbar = ({
12425
+ columns,
12426
+ pivotConfig,
12427
+ onPivotToggle,
12428
+ onConfigChange,
12429
+ isPivotMode = false,
12430
+ style,
12431
+ className
12432
+ }) => {
12433
+ const [isExpanded, setIsExpanded] = (0, import_react33.useState)(isPivotMode);
12434
+ const [rowGroupColumn, setRowGroupColumn] = (0, import_react33.useState)((pivotConfig == null ? void 0 : pivotConfig.rowGroupColumn) || "");
12435
+ const [pivotColumn, setPivotColumn] = (0, import_react33.useState)((pivotConfig == null ? void 0 : pivotConfig.pivotColumn) || "");
12436
+ const [valueColumn, setValueColumn] = (0, import_react33.useState)((pivotConfig == null ? void 0 : pivotConfig.valueColumn) || "");
12437
+ const [aggregator, setAggregator] = (0, import_react33.useState)(
12438
+ (pivotConfig == null ? void 0 : pivotConfig.aggregator) || "sum"
12439
+ );
12440
+ const [showTotals, setShowTotals] = (0, import_react33.useState)((pivotConfig == null ? void 0 : pivotConfig.showTotals) ?? true);
12441
+ const [showGrandTotal, setShowGrandTotal] = (0, import_react33.useState)((pivotConfig == null ? void 0 : pivotConfig.showGrandTotal) ?? true);
12442
+ const isConfigValid = (0, import_react33.useMemo)(() => {
12443
+ return rowGroupColumn && pivotColumn && valueColumn;
12444
+ }, [rowGroupColumn, pivotColumn, valueColumn]);
12445
+ const handleApply = () => {
12446
+ if (!isConfigValid) return;
12447
+ const config = {
12448
+ rowGroupColumn,
12449
+ pivotColumn,
12450
+ valueColumn,
12451
+ aggregator,
12452
+ showTotals,
12453
+ showGrandTotal
12454
+ };
12455
+ onConfigChange(config);
12456
+ onPivotToggle(true);
12457
+ };
12458
+ const handleClear = () => {
12459
+ setRowGroupColumn("");
12460
+ setPivotColumn("");
12461
+ setValueColumn("");
12462
+ setAggregator("sum");
12463
+ setShowTotals(true);
12464
+ setShowGrandTotal(true);
12465
+ onConfigChange(null);
12466
+ onPivotToggle(false);
12467
+ setIsExpanded(false);
12468
+ };
12469
+ const handleToggle = () => {
12470
+ setIsExpanded(!isExpanded);
12471
+ };
12472
+ return /* @__PURE__ */ import_react33.default.createElement(
12473
+ "div",
12474
+ {
12475
+ className,
12476
+ style: {
12477
+ backgroundColor: "#f8fafc",
12478
+ border: "1px solid #e2e8f0",
12479
+ borderRadius: "8px",
12480
+ padding: "12px",
12481
+ ...style
12482
+ }
12483
+ },
12484
+ /* @__PURE__ */ import_react33.default.createElement("div", { style: { display: "flex", alignItems: "center", justifyContent: "space-between", marginBottom: isExpanded ? "12px" : "0" } }, /* @__PURE__ */ import_react33.default.createElement("div", { style: { display: "flex", alignItems: "center", gap: "8px" } }, /* @__PURE__ */ import_react33.default.createElement("span", { style: { fontSize: "20px" } }, "\u{1F4CA}"), /* @__PURE__ */ import_react33.default.createElement("h3", { style: { margin: 0, fontSize: "14px", fontWeight: "600", color: "#1e293b" } }, "Pivot Table"), isPivotMode && /* @__PURE__ */ import_react33.default.createElement("span", { style: {
12485
+ backgroundColor: "#10b981",
12486
+ color: "white",
12487
+ padding: "2px 8px",
12488
+ borderRadius: "12px",
12489
+ fontSize: "11px",
12490
+ fontWeight: "600"
12491
+ } }, "Active")), /* @__PURE__ */ import_react33.default.createElement("div", { style: { display: "flex", gap: "8px" } }, isPivotMode && /* @__PURE__ */ import_react33.default.createElement(
12492
+ "button",
12493
+ {
12494
+ onClick: handleClear,
12495
+ style: {
12496
+ padding: "6px 12px",
12497
+ fontSize: "13px",
12498
+ fontWeight: "500",
12499
+ color: "#dc2626",
12500
+ backgroundColor: "#fee2e2",
12501
+ border: "1px solid #fecaca",
12502
+ borderRadius: "6px",
12503
+ cursor: "pointer",
12504
+ transition: "all 0.15s"
12505
+ },
12506
+ onMouseEnter: (e) => {
12507
+ e.currentTarget.style.backgroundColor = "#fecaca";
12508
+ },
12509
+ onMouseLeave: (e) => {
12510
+ e.currentTarget.style.backgroundColor = "#fee2e2";
12511
+ }
12512
+ },
12513
+ "Clear Pivot"
12514
+ ), /* @__PURE__ */ import_react33.default.createElement(
12515
+ "button",
12516
+ {
12517
+ onClick: handleToggle,
12518
+ style: {
12519
+ padding: "6px 10px",
12520
+ fontSize: "13px",
12521
+ color: "#64748b",
12522
+ backgroundColor: "white",
12523
+ border: "1px solid #cbd5e1",
12524
+ borderRadius: "6px",
12525
+ cursor: "pointer",
12526
+ transition: "all 0.15s"
12527
+ },
12528
+ onMouseEnter: (e) => {
12529
+ e.currentTarget.style.backgroundColor = "#f1f5f9";
12530
+ },
12531
+ onMouseLeave: (e) => {
12532
+ e.currentTarget.style.backgroundColor = "white";
12533
+ }
12534
+ },
12535
+ isExpanded ? "\u25B2" : "\u25BC"
12536
+ ))),
12537
+ isExpanded && /* @__PURE__ */ import_react33.default.createElement("div", { style: { display: "grid", gridTemplateColumns: "repeat(auto-fit, minmax(200px, 1fr))", gap: "12px" } }, /* @__PURE__ */ import_react33.default.createElement("div", null, /* @__PURE__ */ import_react33.default.createElement("label", { style: { display: "block", fontSize: "12px", fontWeight: "600", color: "#475569", marginBottom: "6px" } }, "Row Group By ", /* @__PURE__ */ import_react33.default.createElement("span", { style: { color: "#dc2626" } }, "*")), /* @__PURE__ */ import_react33.default.createElement(
12538
+ "select",
12539
+ {
12540
+ value: rowGroupColumn,
12541
+ onChange: (e) => setRowGroupColumn(e.target.value),
12542
+ style: {
12543
+ width: "100%",
12544
+ padding: "8px",
12545
+ fontSize: "13px",
12546
+ border: "1px solid #cbd5e1",
12547
+ borderRadius: "6px",
12548
+ backgroundColor: "white",
12549
+ color: "#1e293b",
12550
+ cursor: "pointer"
12551
+ }
12552
+ },
12553
+ /* @__PURE__ */ import_react33.default.createElement("option", { value: "" }, "Select column..."),
12554
+ columns.map((col) => /* @__PURE__ */ import_react33.default.createElement("option", { key: col.field, value: col.field }, col.headerName))
12555
+ )), /* @__PURE__ */ import_react33.default.createElement("div", null, /* @__PURE__ */ import_react33.default.createElement("label", { style: { display: "block", fontSize: "12px", fontWeight: "600", color: "#475569", marginBottom: "6px" } }, "Pivot Column ", /* @__PURE__ */ import_react33.default.createElement("span", { style: { color: "#dc2626" } }, "*")), /* @__PURE__ */ import_react33.default.createElement(
12556
+ "select",
12557
+ {
12558
+ value: pivotColumn,
12559
+ onChange: (e) => setPivotColumn(e.target.value),
12560
+ style: {
12561
+ width: "100%",
12562
+ padding: "8px",
12563
+ fontSize: "13px",
12564
+ border: "1px solid #cbd5e1",
12565
+ borderRadius: "6px",
12566
+ backgroundColor: "white",
12567
+ color: "#1e293b",
12568
+ cursor: "pointer"
12569
+ }
12570
+ },
12571
+ /* @__PURE__ */ import_react33.default.createElement("option", { value: "" }, "Select column..."),
12572
+ columns.map((col) => /* @__PURE__ */ import_react33.default.createElement("option", { key: col.field, value: col.field }, col.headerName))
12573
+ )), /* @__PURE__ */ import_react33.default.createElement("div", null, /* @__PURE__ */ import_react33.default.createElement("label", { style: { display: "block", fontSize: "12px", fontWeight: "600", color: "#475569", marginBottom: "6px" } }, "Value Column ", /* @__PURE__ */ import_react33.default.createElement("span", { style: { color: "#dc2626" } }, "*")), /* @__PURE__ */ import_react33.default.createElement(
12574
+ "select",
12575
+ {
12576
+ value: valueColumn,
12577
+ onChange: (e) => setValueColumn(e.target.value),
12578
+ style: {
12579
+ width: "100%",
12580
+ padding: "8px",
12581
+ fontSize: "13px",
12582
+ border: "1px solid #cbd5e1",
12583
+ borderRadius: "6px",
12584
+ backgroundColor: "white",
12585
+ color: "#1e293b",
12586
+ cursor: "pointer"
12587
+ }
12588
+ },
12589
+ /* @__PURE__ */ import_react33.default.createElement("option", { value: "" }, "Select column..."),
12590
+ columns.map((col) => /* @__PURE__ */ import_react33.default.createElement("option", { key: col.field, value: col.field }, col.headerName))
12591
+ )), /* @__PURE__ */ import_react33.default.createElement("div", null, /* @__PURE__ */ import_react33.default.createElement("label", { style: { display: "block", fontSize: "12px", fontWeight: "600", color: "#475569", marginBottom: "6px" } }, "Aggregation"), /* @__PURE__ */ import_react33.default.createElement(
12592
+ "select",
12593
+ {
12594
+ value: aggregator,
12595
+ onChange: (e) => setAggregator(e.target.value),
12596
+ style: {
12597
+ width: "100%",
12598
+ padding: "8px",
12599
+ fontSize: "13px",
12600
+ border: "1px solid #cbd5e1",
12601
+ borderRadius: "6px",
12602
+ backgroundColor: "white",
12603
+ color: "#1e293b",
12604
+ cursor: "pointer"
12605
+ }
12606
+ },
12607
+ AGGREGATOR_OPTIONS.map((opt) => /* @__PURE__ */ import_react33.default.createElement("option", { key: opt.value, value: opt.value }, opt.label))
12608
+ )), /* @__PURE__ */ import_react33.default.createElement("div", { style: { display: "flex", flexDirection: "column", gap: "8px", justifyContent: "center" } }, /* @__PURE__ */ import_react33.default.createElement("label", { style: { display: "flex", alignItems: "center", gap: "6px", fontSize: "13px", color: "#475569", cursor: "pointer" } }, /* @__PURE__ */ import_react33.default.createElement(
12609
+ "input",
12610
+ {
12611
+ type: "checkbox",
12612
+ checked: showTotals,
12613
+ onChange: (e) => setShowTotals(e.target.checked),
12614
+ style: { cursor: "pointer" }
12615
+ }
12616
+ ), "Show Totals Row"), /* @__PURE__ */ import_react33.default.createElement("label", { style: { display: "flex", alignItems: "center", gap: "6px", fontSize: "13px", color: "#475569", cursor: "pointer" } }, /* @__PURE__ */ import_react33.default.createElement(
12617
+ "input",
12618
+ {
12619
+ type: "checkbox",
12620
+ checked: showGrandTotal,
12621
+ onChange: (e) => setShowGrandTotal(e.target.checked),
12622
+ style: { cursor: "pointer" }
12623
+ }
12624
+ ), "Show Grand Total Column")), /* @__PURE__ */ import_react33.default.createElement("div", { style: { display: "flex", alignItems: "flex-end" } }, /* @__PURE__ */ import_react33.default.createElement(
12625
+ "button",
12626
+ {
12627
+ onClick: handleApply,
12628
+ disabled: !isConfigValid,
12629
+ style: {
12630
+ width: "100%",
12631
+ padding: "10px",
12632
+ fontSize: "14px",
12633
+ fontWeight: "600",
12634
+ color: "white",
12635
+ backgroundColor: isConfigValid ? "#2563eb" : "#94a3b8",
12636
+ border: "none",
12637
+ borderRadius: "6px",
12638
+ cursor: isConfigValid ? "pointer" : "not-allowed",
12639
+ transition: "all 0.15s",
12640
+ boxShadow: isConfigValid ? "0 2px 4px rgba(37, 99, 235, 0.2)" : "none"
12641
+ },
12642
+ onMouseEnter: (e) => {
12643
+ if (isConfigValid) {
12644
+ e.currentTarget.style.backgroundColor = "#1d4ed8";
12645
+ }
12646
+ },
12647
+ onMouseLeave: (e) => {
12648
+ if (isConfigValid) {
12649
+ e.currentTarget.style.backgroundColor = "#2563eb";
12650
+ }
12651
+ }
12652
+ },
12653
+ "Apply Pivot"
12654
+ ))),
12655
+ isExpanded && /* @__PURE__ */ import_react33.default.createElement("div", { style: {
12656
+ marginTop: "12px",
12657
+ padding: "10px",
12658
+ backgroundColor: "#eff6ff",
12659
+ border: "1px solid #bfdbfe",
12660
+ borderRadius: "6px",
12661
+ fontSize: "12px",
12662
+ color: "#1e40af"
12663
+ } }, /* @__PURE__ */ import_react33.default.createElement("strong", null, "\u{1F4A1} Tip:"), " Select a Row Group column to organize data by, a Pivot column whose values become new columns, and a Value column to aggregate.")
12664
+ );
12665
+ };
12666
+
12667
+ // src/editors/editorUtils.ts
12668
+ var import_react34 = require("react");
12669
+ function useEditorKeyboardNavigation(handlers, config = {}) {
12670
+ const {
12671
+ commitOnEnter = true,
12672
+ cancelOnEscape = true,
12673
+ commitOnTab = true,
12674
+ preventDefault = true,
12675
+ stopPropagation = true
12676
+ } = config;
12677
+ const handleKeyDown = (0, import_react34.useCallback)(
12678
+ (event) => {
12679
+ let handled = false;
12680
+ switch (event.key) {
12681
+ case "Enter":
12682
+ if (commitOnEnter && handlers.onEnter) {
12683
+ handlers.onEnter();
12684
+ handled = true;
12685
+ }
12686
+ break;
12687
+ case "Escape":
12688
+ if (cancelOnEscape && handlers.onEscape) {
12689
+ handlers.onEscape();
12690
+ handled = true;
12691
+ }
12692
+ break;
12693
+ case "Tab":
12694
+ if (commitOnTab && handlers.onTab) {
12695
+ handlers.onTab(event.shiftKey);
12696
+ handled = true;
12697
+ }
12698
+ break;
12699
+ case "ArrowUp":
12700
+ if (handlers.onArrowUp) {
12701
+ handlers.onArrowUp();
12702
+ handled = true;
12703
+ }
12704
+ break;
12705
+ case "ArrowDown":
12706
+ if (handlers.onArrowDown) {
12707
+ handlers.onArrowDown();
12708
+ handled = true;
12709
+ }
12710
+ break;
12711
+ }
12712
+ if (handled) {
12713
+ if (preventDefault) {
12714
+ event.preventDefault();
12715
+ }
12716
+ if (stopPropagation) {
12717
+ event.stopPropagation();
12718
+ }
12719
+ }
12720
+ },
12721
+ [
12722
+ handlers,
12723
+ commitOnEnter,
12724
+ cancelOnEscape,
12725
+ commitOnTab,
12726
+ preventDefault,
12727
+ stopPropagation
12728
+ ]
12729
+ );
12730
+ return { handleKeyDown };
12731
+ }
12732
+ function useEditorAutoFocus(autoFocus = true, selectAll = false) {
12733
+ const elementRef = (0, import_react34.useRef)(null);
12734
+ (0, import_react34.useEffect)(() => {
12735
+ if (autoFocus && elementRef.current) {
12736
+ elementRef.current.focus();
12737
+ if (selectAll && elementRef.current instanceof HTMLInputElement) {
12738
+ elementRef.current.select();
12739
+ }
12740
+ }
12741
+ }, [autoFocus, selectAll]);
12742
+ return elementRef;
12743
+ }
12744
+ function useEditorClickOutside(ref, onClickOutside, enabled = true) {
12745
+ (0, import_react34.useEffect)(() => {
12746
+ if (!enabled) return;
12747
+ const handleClickOutside = (event) => {
12748
+ if (ref.current && !ref.current.contains(event.target)) {
12749
+ onClickOutside();
12750
+ }
12751
+ };
12752
+ const timeoutId = setTimeout(() => {
12753
+ document.addEventListener("mousedown", handleClickOutside);
12754
+ }, 0);
12755
+ return () => {
12756
+ clearTimeout(timeoutId);
12757
+ document.removeEventListener("mousedown", handleClickOutside);
12758
+ };
12759
+ }, [ref, onClickOutside, enabled]);
12760
+ }
12761
+ function usePopupPosition(anchorRef, popupRef, isOpen, placement = "auto") {
12762
+ (0, import_react34.useEffect)(() => {
12763
+ if (!isOpen || !anchorRef.current || !popupRef.current) return;
12764
+ const anchor = anchorRef.current;
12765
+ const popup = popupRef.current;
12766
+ const anchorRect = anchor.getBoundingClientRect();
12767
+ const popupRect = popup.getBoundingClientRect();
12768
+ const viewportHeight = window.innerHeight;
12769
+ const viewportWidth = window.innerWidth;
12770
+ let top = 0;
12771
+ let left = 0;
12772
+ let actualPlacement = placement;
12773
+ if (placement === "auto") {
12774
+ const spaceBelow = viewportHeight - anchorRect.bottom;
12775
+ const spaceAbove = anchorRect.top;
12776
+ const spaceRight = viewportWidth - anchorRect.right;
12777
+ const spaceLeft = anchorRect.left;
12778
+ if (spaceBelow >= popupRect.height || spaceBelow >= spaceAbove) {
12779
+ actualPlacement = "bottom";
12780
+ } else if (spaceAbove >= popupRect.height) {
12781
+ actualPlacement = "top";
12782
+ } else if (spaceRight >= popupRect.width) {
12783
+ actualPlacement = "right";
12784
+ } else if (spaceLeft >= popupRect.width) {
12785
+ actualPlacement = "left";
12786
+ } else {
12787
+ actualPlacement = "bottom";
12788
+ }
12789
+ }
12790
+ switch (actualPlacement) {
12791
+ case "bottom":
12792
+ top = anchorRect.bottom + window.scrollY;
12793
+ left = anchorRect.left + window.scrollX;
12794
+ break;
12795
+ case "top":
12796
+ top = anchorRect.top + window.scrollY - popupRect.height;
12797
+ left = anchorRect.left + window.scrollX;
12798
+ break;
12799
+ case "right":
12800
+ top = anchorRect.top + window.scrollY;
12801
+ left = anchorRect.right + window.scrollX;
12802
+ break;
12803
+ case "left":
12804
+ top = anchorRect.top + window.scrollY;
12805
+ left = anchorRect.left + window.scrollX - popupRect.width;
12806
+ break;
12807
+ }
12808
+ const margin = 8;
12809
+ if (left + popupRect.width > viewportWidth) {
12810
+ left = viewportWidth - popupRect.width - margin;
12811
+ }
12812
+ if (left < margin) {
12813
+ left = margin;
12814
+ }
12815
+ if (top + popupRect.height > viewportHeight + window.scrollY) {
12816
+ top = viewportHeight + window.scrollY - popupRect.height - margin;
12817
+ }
12818
+ if (top < window.scrollY + margin) {
12819
+ top = window.scrollY + margin;
12820
+ }
12821
+ popup.style.top = `${top}px`;
12822
+ popup.style.left = `${left}px`;
12823
+ popup.style.minWidth = `${anchorRect.width}px`;
12824
+ }, [isOpen, anchorRef, popupRef, placement]);
12825
+ }
12826
+ function debounce2(func, wait) {
12827
+ let timeout = null;
12828
+ return function executedFunction(...args) {
12829
+ const later = () => {
12830
+ timeout = null;
12831
+ func(...args);
12832
+ };
12833
+ if (timeout) {
12834
+ clearTimeout(timeout);
12835
+ }
12836
+ timeout = setTimeout(later, wait);
12837
+ };
12838
+ }
12839
+ function formatNumber(value, decimals = 0, thousandsSeparator = ",", decimalSeparator = ".") {
12840
+ const fixed = value.toFixed(decimals);
12841
+ const [integerPart, decimalPart] = fixed.split(".");
12842
+ const formattedInteger = integerPart.replace(
12843
+ /\B(?=(\d{3})+(?!\d))/g,
12844
+ thousandsSeparator
12845
+ );
12846
+ return decimalPart ? `${formattedInteger}${decimalSeparator}${decimalPart}` : formattedInteger;
12847
+ }
12848
+ function parseFormattedNumber(value, thousandsSeparator = ",", decimalSeparator = ".") {
12849
+ if (!value || typeof value !== "string") return null;
12850
+ const normalized = value.replace(new RegExp(`\\${thousandsSeparator}`, "g"), "").replace(new RegExp(`\\${decimalSeparator}`), ".");
12851
+ const parsed = parseFloat(normalized);
12852
+ return isNaN(parsed) ? null : parsed;
12853
+ }
12854
+ function filterOptions(options, searchQuery) {
12855
+ if (!searchQuery.trim()) return options;
12856
+ const lowerQuery = searchQuery.toLowerCase();
12857
+ return options.filter(
12858
+ (option) => option.label.toLowerCase().includes(lowerQuery)
12859
+ );
12860
+ }
12861
+
12862
+ // src/editors/RichSelectEditor.tsx
12863
+ var import_react35 = __toESM(require("react"), 1);
12864
+ function RichSelectEditor(props) {
12865
+ const {
12866
+ value,
12867
+ onChange,
12868
+ onCommit,
12869
+ onCancel,
12870
+ autoFocus = true,
12871
+ options,
12872
+ placeholder = "Select...",
12873
+ allowClear = false,
12874
+ filterable = true,
12875
+ renderOptionLabel,
12876
+ maxDropdownHeight = 300
12877
+ } = props;
12878
+ const [isOpen] = (0, import_react35.useState)(true);
12879
+ const [searchQuery, setSearchQuery] = (0, import_react35.useState)("");
12880
+ const [focusedIndex, setFocusedIndex] = (0, import_react35.useState)(-1);
12881
+ const containerRef = (0, import_react35.useRef)(null);
12882
+ const inputRef = useEditorAutoFocus(autoFocus, true);
12883
+ const dropdownRef = (0, import_react35.useRef)(null);
12884
+ const optionRefs = (0, import_react35.useRef)([]);
12885
+ const filteredOptions = (0, import_react35.useMemo)(
12886
+ () => filterable ? filterOptions(options, searchQuery) : options,
12887
+ [options, searchQuery, filterable]
12888
+ );
12889
+ const selectedOption = (0, import_react35.useMemo)(
12890
+ () => options.find((opt) => opt.value === value),
12891
+ [options, value]
12892
+ );
12893
+ (0, import_react35.useEffect)(() => {
12894
+ if (selectedOption) {
12895
+ const index = filteredOptions.findIndex(
12896
+ (opt) => opt.value === selectedOption.value
12897
+ );
12898
+ if (index !== -1 && focusedIndex === -1) {
12899
+ queueMicrotask(() => setFocusedIndex(index));
12900
+ }
12901
+ }
12902
+ }, [selectedOption, filteredOptions]);
12903
+ (0, import_react35.useEffect)(() => {
12904
+ var _a;
12905
+ if (focusedIndex >= 0 && optionRefs.current[focusedIndex]) {
12906
+ (_a = optionRefs.current[focusedIndex]) == null ? void 0 : _a.scrollIntoView({
12907
+ block: "nearest",
12908
+ behavior: "smooth"
12909
+ });
12910
+ }
12911
+ }, [focusedIndex]);
12912
+ usePopupPosition(containerRef, dropdownRef, isOpen, "auto");
12913
+ useEditorClickOutside(
12914
+ containerRef,
12915
+ () => {
12916
+ if (isOpen) {
12917
+ onCommit();
12918
+ }
12919
+ },
12920
+ true
12921
+ );
12922
+ const handleSelectOption = (option) => {
12923
+ if (!option.disabled) {
12924
+ onChange(option.value);
12925
+ onCommit();
12926
+ }
12927
+ };
12928
+ const handleClear = (e) => {
12929
+ e.stopPropagation();
12930
+ onChange(null);
12931
+ setSearchQuery("");
12932
+ setFocusedIndex(-1);
12933
+ };
12934
+ const handleArrowDown = () => {
12935
+ setFocusedIndex((prev) => {
12936
+ var _a;
12937
+ let next = prev + 1;
12938
+ while (next < filteredOptions.length && ((_a = filteredOptions[next]) == null ? void 0 : _a.disabled)) {
12939
+ next++;
12940
+ }
12941
+ return next < filteredOptions.length ? next : prev;
12942
+ });
12943
+ };
12944
+ const handleArrowUp = () => {
12945
+ setFocusedIndex((prev) => {
12946
+ var _a;
12947
+ let next = prev - 1;
12948
+ while (next >= 0 && ((_a = filteredOptions[next]) == null ? void 0 : _a.disabled)) {
12949
+ next--;
12950
+ }
12951
+ return next >= 0 ? next : prev;
12952
+ });
12953
+ };
12954
+ const handleEnter = () => {
12955
+ if (focusedIndex >= 0 && focusedIndex < filteredOptions.length) {
12956
+ const option = filteredOptions[focusedIndex];
12957
+ if (option && !option.disabled) {
12958
+ handleSelectOption(option);
12959
+ }
12960
+ } else {
12961
+ onCommit();
12962
+ }
12963
+ };
12964
+ const { handleKeyDown } = useEditorKeyboardNavigation(
12965
+ {
12966
+ onEnter: handleEnter,
12967
+ onEscape: onCancel,
12968
+ onArrowUp: handleArrowUp,
12969
+ onArrowDown: handleArrowDown
12970
+ },
12971
+ {
12972
+ commitOnTab: true,
12973
+ commitOnBlur: false
12974
+ }
12975
+ );
12976
+ const renderLabel = (option) => {
12977
+ if (renderOptionLabel) {
12978
+ return renderOptionLabel(option);
12979
+ }
12980
+ return /* @__PURE__ */ import_react35.default.createElement("div", { className: "editor-option-content" }, option.icon && /* @__PURE__ */ import_react35.default.createElement("span", { className: "editor-option-icon" }, option.icon), /* @__PURE__ */ import_react35.default.createElement("div", { className: "editor-option-text" }, /* @__PURE__ */ import_react35.default.createElement("div", { className: "editor-option-label" }, option.label), option.description && /* @__PURE__ */ import_react35.default.createElement("div", { className: "editor-option-description" }, option.description)));
12981
+ };
12982
+ return /* @__PURE__ */ import_react35.default.createElement(
12983
+ "div",
12984
+ {
12985
+ ref: containerRef,
12986
+ className: "editor-container editor-richselect-container",
12987
+ onKeyDown: handleKeyDown
12988
+ },
12989
+ /* @__PURE__ */ import_react35.default.createElement("div", { className: "editor-input-wrapper" }, /* @__PURE__ */ import_react35.default.createElement(
12990
+ "input",
12991
+ {
12992
+ ref: inputRef,
12993
+ type: "text",
12994
+ className: "editor-input editor-richselect-input",
12995
+ value: filterable ? searchQuery : (selectedOption == null ? void 0 : selectedOption.label) || "",
12996
+ onChange: (e) => {
12997
+ if (filterable) {
12998
+ setSearchQuery(e.target.value);
12999
+ setFocusedIndex(-1);
13000
+ }
13001
+ },
13002
+ placeholder: (selectedOption == null ? void 0 : selectedOption.label) || placeholder,
13003
+ "aria-label": "Select option",
13004
+ "aria-expanded": isOpen,
13005
+ "aria-autocomplete": "list",
13006
+ "aria-controls": "richselect-dropdown",
13007
+ autoComplete: "off"
13008
+ }
13009
+ ), /* @__PURE__ */ import_react35.default.createElement("div", { className: "editor-input-actions" }, allowClear && value !== null && value !== void 0 && /* @__PURE__ */ import_react35.default.createElement(
13010
+ "button",
13011
+ {
13012
+ type: "button",
13013
+ className: "editor-clear-btn",
13014
+ onClick: handleClear,
13015
+ "aria-label": "Clear selection",
13016
+ tabIndex: -1
13017
+ },
13018
+ "\xD7"
13019
+ ), /* @__PURE__ */ import_react35.default.createElement("span", { className: "editor-dropdown-icon", "aria-hidden": "true" }, "\u25BC"))),
13020
+ isOpen && /* @__PURE__ */ import_react35.default.createElement(
13021
+ "div",
13022
+ {
13023
+ ref: dropdownRef,
13024
+ id: "richselect-dropdown",
13025
+ className: "editor-dropdown",
13026
+ role: "listbox",
13027
+ style: { maxHeight: maxDropdownHeight }
13028
+ },
13029
+ filteredOptions.length === 0 ? /* @__PURE__ */ import_react35.default.createElement("div", { className: "editor-dropdown-empty" }, "No options found") : filteredOptions.map((option, index) => /* @__PURE__ */ import_react35.default.createElement(
13030
+ "div",
13031
+ {
13032
+ key: option.value,
13033
+ ref: (el) => {
13034
+ optionRefs.current[index] = el;
13035
+ },
13036
+ className: `editor-dropdown-option ${option.value === value ? "selected" : ""} ${option.disabled ? "disabled" : ""} ${index === focusedIndex ? "focused" : ""}`,
13037
+ role: "option",
13038
+ "aria-selected": option.value === value,
13039
+ "aria-disabled": option.disabled,
13040
+ onClick: () => handleSelectOption(option),
13041
+ onMouseEnter: () => !option.disabled && setFocusedIndex(index)
13042
+ },
13043
+ renderLabel(option)
13044
+ ))
13045
+ )
13046
+ );
13047
+ }
13048
+ RichSelectEditor.displayName = "RichSelectEditor";
13049
+
13050
+ // src/editors/DateEditor.tsx
13051
+ var import_react36 = __toESM(require("react"), 1);
13052
+ function DateEditor(props) {
13053
+ const {
13054
+ value,
13055
+ onChange,
13056
+ onCommit,
13057
+ onCancel,
13058
+ autoFocus = true,
13059
+ dateFormat = "yyyy-MM-dd",
13060
+ showTime = false,
13061
+ minDate,
13062
+ maxDate,
13063
+ autoCommit = false
13064
+ } = props;
13065
+ const [isOpen] = (0, import_react36.useState)(true);
13066
+ const [inputValue, setInputValue] = (0, import_react36.useState)("");
13067
+ const [viewDate, setViewDate] = (0, import_react36.useState)(/* @__PURE__ */ new Date());
13068
+ const containerRef = (0, import_react36.useRef)(null);
13069
+ const inputRef = useEditorAutoFocus(autoFocus, true);
13070
+ const calendarRef = (0, import_react36.useRef)(null);
13071
+ const parsedValue = (0, import_react36.useMemo)(() => {
13072
+ if (!value) return null;
13073
+ if (value instanceof Date) return value;
13074
+ const parsed = new Date(value);
13075
+ return isNaN(parsed.getTime()) ? null : parsed;
13076
+ }, [value]);
13077
+ import_react36.default.useEffect(() => {
13078
+ if (parsedValue) {
13079
+ setInputValue(formatDate(parsedValue, dateFormat, showTime));
13080
+ setViewDate(parsedValue);
13081
+ }
13082
+ }, [parsedValue, dateFormat, showTime]);
13083
+ usePopupPosition(containerRef, calendarRef, isOpen, "auto");
13084
+ useEditorClickOutside(containerRef, () => {
13085
+ if (isOpen) {
13086
+ onCommit();
13087
+ }
13088
+ }, true);
13089
+ const handleSelectDate = (date) => {
13090
+ const newDate = new Date(date);
13091
+ if (parsedValue && !showTime) {
13092
+ newDate.setHours(parsedValue.getHours());
13093
+ newDate.setMinutes(parsedValue.getMinutes());
13094
+ newDate.setSeconds(parsedValue.getSeconds());
13095
+ }
13096
+ onChange(newDate);
13097
+ setInputValue(formatDate(newDate, dateFormat, showTime));
13098
+ if (autoCommit && !showTime) {
13099
+ onCommit();
13100
+ }
13101
+ };
13102
+ const handleTimeChange = (hours, minutes) => {
13103
+ const newDate = parsedValue ? new Date(parsedValue) : /* @__PURE__ */ new Date();
13104
+ newDate.setHours(hours);
13105
+ newDate.setMinutes(minutes);
13106
+ onChange(newDate);
13107
+ setInputValue(formatDate(newDate, dateFormat, showTime));
13108
+ };
13109
+ const handleInputChange = (e) => {
13110
+ const newValue = e.target.value;
13111
+ setInputValue(newValue);
13112
+ const parsed = parseDate(newValue, dateFormat);
13113
+ if (parsed && !isNaN(parsed.getTime())) {
13114
+ onChange(parsed);
13115
+ setViewDate(parsed);
13116
+ }
13117
+ };
13118
+ const handleInputBlur = () => {
13119
+ if (parsedValue) {
13120
+ setInputValue(formatDate(parsedValue, dateFormat, showTime));
13121
+ }
13122
+ };
13123
+ const handlePrevMonth = () => {
13124
+ setViewDate((prev) => {
13125
+ const newDate = new Date(prev);
13126
+ newDate.setMonth(newDate.getMonth() - 1);
13127
+ return newDate;
13128
+ });
13129
+ };
13130
+ const handleNextMonth = () => {
13131
+ setViewDate((prev) => {
13132
+ const newDate = new Date(prev);
13133
+ newDate.setMonth(newDate.getMonth() + 1);
13134
+ return newDate;
13135
+ });
13136
+ };
13137
+ const { handleKeyDown } = useEditorKeyboardNavigation(
13138
+ {
13139
+ onEnter: onCommit,
13140
+ onEscape: onCancel
13141
+ },
13142
+ {
13143
+ commitOnTab: true,
13144
+ commitOnBlur: false
13145
+ }
13146
+ );
13147
+ const calendarDays = (0, import_react36.useMemo)(() => {
13148
+ return generateCalendarDays(viewDate, parsedValue, minDate, maxDate);
13149
+ }, [viewDate, parsedValue, minDate, maxDate]);
13150
+ return /* @__PURE__ */ import_react36.default.createElement(
13151
+ "div",
13152
+ {
13153
+ ref: containerRef,
13154
+ className: "editor-container editor-date-container",
13155
+ onKeyDown: handleKeyDown
13156
+ },
13157
+ /* @__PURE__ */ import_react36.default.createElement("div", { className: "editor-input-wrapper" }, /* @__PURE__ */ import_react36.default.createElement(
13158
+ "input",
13159
+ {
13160
+ ref: inputRef,
13161
+ type: "text",
13162
+ className: "editor-input editor-date-input",
13163
+ value: inputValue,
13164
+ onChange: handleInputChange,
13165
+ onBlur: handleInputBlur,
13166
+ placeholder: dateFormat,
13167
+ "aria-label": "Date input",
13168
+ autoComplete: "off"
13169
+ }
13170
+ ), /* @__PURE__ */ import_react36.default.createElement("span", { className: "editor-calendar-icon", "aria-hidden": "true" }, "\u{1F4C5}")),
13171
+ isOpen && /* @__PURE__ */ import_react36.default.createElement("div", { ref: calendarRef, className: "editor-dropdown editor-calendar" }, /* @__PURE__ */ import_react36.default.createElement("div", { className: "editor-calendar-header" }, /* @__PURE__ */ import_react36.default.createElement(
13172
+ "button",
13173
+ {
13174
+ type: "button",
13175
+ className: "editor-calendar-nav",
13176
+ onClick: handlePrevMonth,
13177
+ "aria-label": "Previous month"
13178
+ },
13179
+ "\u2039"
13180
+ ), /* @__PURE__ */ import_react36.default.createElement("div", { className: "editor-calendar-title" }, viewDate.toLocaleDateString("en-US", {
13181
+ month: "long",
13182
+ year: "numeric"
13183
+ })), /* @__PURE__ */ import_react36.default.createElement(
13184
+ "button",
13185
+ {
13186
+ type: "button",
13187
+ className: "editor-calendar-nav",
13188
+ onClick: handleNextMonth,
13189
+ "aria-label": "Next month"
13190
+ },
13191
+ "\u203A"
13192
+ )), /* @__PURE__ */ import_react36.default.createElement("div", { className: "editor-calendar-weekdays" }, ["Su", "Mo", "Tu", "We", "Th", "Fr", "Sa"].map((day) => /* @__PURE__ */ import_react36.default.createElement("div", { key: day, className: "editor-calendar-weekday" }, day))), /* @__PURE__ */ import_react36.default.createElement("div", { className: "editor-calendar-days" }, calendarDays.map((day, index) => /* @__PURE__ */ import_react36.default.createElement(
13193
+ "button",
13194
+ {
13195
+ key: index,
13196
+ type: "button",
13197
+ className: `editor-calendar-day ${day.className}`,
13198
+ onClick: () => day.date && handleSelectDate(day.date),
13199
+ disabled: day.disabled,
13200
+ "aria-label": day.date ? day.date.toDateString() : ""
13201
+ },
13202
+ day.label
13203
+ ))), showTime && /* @__PURE__ */ import_react36.default.createElement("div", { className: "editor-calendar-time" }, /* @__PURE__ */ import_react36.default.createElement(
13204
+ "input",
13205
+ {
13206
+ type: "time",
13207
+ className: "editor-time-input",
13208
+ value: parsedValue ? `${String(parsedValue.getHours()).padStart(2, "0")}:${String(
13209
+ parsedValue.getMinutes()
13210
+ ).padStart(2, "0")}` : "00:00",
13211
+ onChange: (e) => {
13212
+ const [hours, minutes] = e.target.value.split(":").map(Number);
13213
+ handleTimeChange(hours, minutes);
13214
+ },
13215
+ "aria-label": "Time input"
13216
+ }
13217
+ )))
13218
+ );
13219
+ }
13220
+ DateEditor.displayName = "DateEditor";
13221
+ function formatDate(date, format, showTime) {
13222
+ const year = date.getFullYear();
13223
+ const month = String(date.getMonth() + 1).padStart(2, "0");
13224
+ const day = String(date.getDate()).padStart(2, "0");
13225
+ const hours = String(date.getHours()).padStart(2, "0");
13226
+ const minutes = String(date.getMinutes()).padStart(2, "0");
13227
+ let formatted = format.replace("yyyy", String(year)).replace("MM", month).replace("dd", day);
13228
+ if (showTime) {
13229
+ formatted += ` ${hours}:${minutes}`;
13230
+ }
13231
+ return formatted;
13232
+ }
13233
+ function parseDate(value, format) {
13234
+ if (!value) return null;
13235
+ try {
13236
+ const parts = value.split(/[-/\s:]/);
13237
+ if (parts.length < 3) return null;
13238
+ let year, month, day;
13239
+ let hours = 0, minutes = 0;
13240
+ if (format.startsWith("yyyy")) {
13241
+ year = parseInt(parts[0], 10);
13242
+ month = parseInt(parts[1], 10) - 1;
13243
+ day = parseInt(parts[2], 10);
13244
+ } else if (format.startsWith("MM")) {
13245
+ month = parseInt(parts[0], 10) - 1;
13246
+ day = parseInt(parts[1], 10);
13247
+ year = parseInt(parts[2], 10);
13248
+ } else {
13249
+ day = parseInt(parts[0], 10);
13250
+ month = parseInt(parts[1], 10) - 1;
13251
+ year = parseInt(parts[2], 10);
13252
+ }
13253
+ if (parts.length >= 5) {
13254
+ hours = parseInt(parts[3], 10);
13255
+ minutes = parseInt(parts[4], 10);
13256
+ }
13257
+ const date = new Date(year, month, day, hours, minutes);
13258
+ return isNaN(date.getTime()) ? null : date;
13259
+ } catch {
13260
+ return null;
13261
+ }
13262
+ }
13263
+ function generateCalendarDays(viewDate, selectedDate, minDate, maxDate) {
13264
+ const year = viewDate.getFullYear();
13265
+ const month = viewDate.getMonth();
13266
+ const firstDay = new Date(year, month, 1);
13267
+ const lastDay = new Date(year, month + 1, 0);
13268
+ const daysInMonth = lastDay.getDate();
13269
+ const startingDayOfWeek = firstDay.getDay();
13270
+ const days = [];
13271
+ const prevMonth = new Date(year, month, 0);
13272
+ const prevMonthDays = prevMonth.getDate();
13273
+ for (let i = startingDayOfWeek - 1; i >= 0; i--) {
13274
+ const date = new Date(year, month - 1, prevMonthDays - i);
13275
+ days.push({
13276
+ date,
13277
+ label: String(prevMonthDays - i),
13278
+ className: "other-month",
13279
+ disabled: isDateDisabled(date, minDate, maxDate)
13280
+ });
13281
+ }
13282
+ for (let i = 1; i <= daysInMonth; i++) {
13283
+ const date = new Date(year, month, i);
13284
+ const isSelected = selectedDate && isSameDay(date, selectedDate);
13285
+ const isToday = isSameDay(date, /* @__PURE__ */ new Date());
13286
+ const disabled = isDateDisabled(date, minDate, maxDate);
13287
+ days.push({
13288
+ date,
13289
+ label: String(i),
13290
+ className: `${isSelected ? "selected" : ""} ${isToday ? "today" : ""} ${disabled ? "disabled" : ""}`.trim(),
13291
+ disabled
13292
+ });
13293
+ }
13294
+ const remainingDays = 42 - days.length;
13295
+ for (let i = 1; i <= remainingDays; i++) {
13296
+ const date = new Date(year, month + 1, i);
13297
+ days.push({
13298
+ date,
13299
+ label: String(i),
13300
+ className: "other-month",
13301
+ disabled: isDateDisabled(date, minDate, maxDate)
13302
+ });
13303
+ }
13304
+ return days;
13305
+ }
13306
+ function isSameDay(date1, date2) {
13307
+ return date1.getFullYear() === date2.getFullYear() && date1.getMonth() === date2.getMonth() && date1.getDate() === date2.getDate();
13308
+ }
13309
+ function isDateDisabled(date, minDate, maxDate) {
13310
+ if (minDate && date < minDate) return true;
13311
+ if (maxDate && date > maxDate) return true;
13312
+ return false;
13313
+ }
13314
+
13315
+ // src/editors/NumericEditor.tsx
13316
+ var import_react37 = __toESM(require("react"), 1);
13317
+ function NumericEditor(props) {
13318
+ const {
13319
+ value,
13320
+ onChange,
13321
+ onCommit,
13322
+ onCancel,
13323
+ autoFocus = true,
13324
+ min,
13325
+ max,
13326
+ step = 1,
13327
+ decimals = 0,
13328
+ prefix = "",
13329
+ suffix = "",
13330
+ allowNegative = true,
13331
+ showSteppers = true,
13332
+ thousandsSeparator = ",",
13333
+ decimalSeparator = "."
13334
+ } = props;
13335
+ const [inputValue, setInputValue] = (0, import_react37.useState)("");
13336
+ const [isFocused, setIsFocused] = (0, import_react37.useState)(true);
13337
+ const inputRef = useEditorAutoFocus(autoFocus, true);
13338
+ (0, import_react37.useEffect)(() => {
13339
+ if (value !== null && value !== void 0) {
13340
+ if (isFocused) {
13341
+ queueMicrotask(() => setInputValue(String(value)));
13342
+ } else {
13343
+ queueMicrotask(() => setInputValue(formatNumber(value, decimals, thousandsSeparator, decimalSeparator)));
13344
+ }
13345
+ } else {
13346
+ queueMicrotask(() => setInputValue(""));
13347
+ }
13348
+ }, [value, isFocused, decimals, thousandsSeparator, decimalSeparator]);
13349
+ const clampValue = (val) => {
13350
+ let clamped = val;
13351
+ if (min !== void 0 && clamped < min) clamped = min;
13352
+ if (max !== void 0 && clamped > max) clamped = max;
13353
+ return clamped;
13354
+ };
13355
+ const handleInputChange = (e) => {
13356
+ const newValue = e.target.value;
13357
+ setInputValue(newValue);
13358
+ if (newValue === "" || newValue === "-") {
13359
+ onChange(null);
13360
+ return;
13361
+ }
13362
+ let cleaned = newValue;
13363
+ if (prefix) cleaned = cleaned.replace(prefix, "");
13364
+ if (suffix) cleaned = cleaned.replace(suffix, "");
13365
+ const parsed = parseFormattedNumber(cleaned, thousandsSeparator, decimalSeparator);
13366
+ if (parsed !== null && !isNaN(parsed)) {
13367
+ if (!allowNegative && parsed < 0) {
13368
+ return;
13369
+ }
13370
+ const clamped = clampValue(parsed);
13371
+ onChange(clamped);
13372
+ }
13373
+ };
13374
+ const handleIncrement = () => {
13375
+ const currentValue = value ?? 0;
13376
+ const newValue = clampValue(currentValue + step);
13377
+ onChange(newValue);
13378
+ setInputValue(String(newValue));
13379
+ };
13380
+ const handleDecrement = () => {
13381
+ const currentValue = value ?? 0;
13382
+ const newValue = clampValue(currentValue - step);
13383
+ onChange(newValue);
13384
+ setInputValue(String(newValue));
13385
+ };
13386
+ const handleFocus = () => {
13387
+ setIsFocused(true);
13388
+ if (value !== null && value !== void 0) {
13389
+ setInputValue(String(value));
13390
+ }
13391
+ };
13392
+ const handleBlur = () => {
13393
+ setIsFocused(false);
13394
+ if (value !== null && value !== void 0) {
13395
+ const formatted = formatNumber(value, decimals, thousandsSeparator, decimalSeparator);
13396
+ setInputValue(formatted);
13397
+ }
13398
+ setTimeout(() => onCommit(), 100);
13399
+ };
13400
+ const handleKeyDown = (e) => {
13401
+ if (e.key === "ArrowUp") {
13402
+ e.preventDefault();
13403
+ handleIncrement();
13404
+ } else if (e.key === "ArrowDown") {
13405
+ e.preventDefault();
13406
+ handleDecrement();
13407
+ }
13408
+ };
13409
+ const { handleKeyDown: handleEditorKeyDown } = useEditorKeyboardNavigation(
13410
+ {
13411
+ onEnter: onCommit,
13412
+ onEscape: onCancel
13413
+ },
13414
+ {
13415
+ commitOnTab: true,
13416
+ commitOnBlur: false,
13417
+ preventDefault: false
13418
+ // Let handleKeyDown handle arrow keys
13419
+ }
13420
+ );
13421
+ const handleCombinedKeyDown = (e) => {
13422
+ handleKeyDown(e);
13423
+ handleEditorKeyDown(e);
13424
+ };
13425
+ const displayValue = isFocused ? inputValue : inputValue ? `${prefix}${inputValue}${suffix}` : "";
13426
+ return /* @__PURE__ */ import_react37.default.createElement("div", { className: "editor-container editor-numeric-container" }, /* @__PURE__ */ import_react37.default.createElement("div", { className: "editor-input-wrapper" }, prefix && !isFocused && /* @__PURE__ */ import_react37.default.createElement("span", { className: "editor-numeric-prefix" }, prefix), /* @__PURE__ */ import_react37.default.createElement(
13427
+ "input",
13428
+ {
13429
+ ref: inputRef,
13430
+ type: "text",
13431
+ inputMode: "decimal",
13432
+ className: "editor-input editor-numeric-input",
13433
+ value: displayValue,
13434
+ onChange: handleInputChange,
13435
+ onFocus: handleFocus,
13436
+ onBlur: handleBlur,
13437
+ onKeyDown: handleCombinedKeyDown,
13438
+ "aria-label": "Numeric input",
13439
+ "aria-valuemin": min,
13440
+ "aria-valuemax": max,
13441
+ "aria-valuenow": value ?? void 0,
13442
+ autoComplete: "off"
13443
+ }
13444
+ ), suffix && !isFocused && /* @__PURE__ */ import_react37.default.createElement("span", { className: "editor-numeric-suffix" }, suffix), showSteppers && /* @__PURE__ */ import_react37.default.createElement("div", { className: "editor-numeric-steppers" }, /* @__PURE__ */ import_react37.default.createElement(
13445
+ "button",
13446
+ {
13447
+ type: "button",
13448
+ className: "editor-numeric-stepper editor-numeric-increment",
13449
+ onClick: handleIncrement,
13450
+ onMouseDown: (e) => e.preventDefault(),
13451
+ disabled: max !== void 0 && (value ?? 0) >= max,
13452
+ "aria-label": "Increment",
13453
+ tabIndex: -1
13454
+ },
13455
+ "\u25B2"
13456
+ ), /* @__PURE__ */ import_react37.default.createElement(
13457
+ "button",
13458
+ {
13459
+ type: "button",
13460
+ className: "editor-numeric-stepper editor-numeric-decrement",
13461
+ onClick: handleDecrement,
13462
+ onMouseDown: (e) => e.preventDefault(),
13463
+ disabled: min !== void 0 && (value ?? 0) <= min,
13464
+ "aria-label": "Decrement",
13465
+ tabIndex: -1
13466
+ },
13467
+ "\u25BC"
13468
+ ))), (min !== void 0 || max !== void 0) && /* @__PURE__ */ import_react37.default.createElement("div", { className: "editor-numeric-range" }, min !== void 0 && /* @__PURE__ */ import_react37.default.createElement("span", null, "Min: ", min), max !== void 0 && /* @__PURE__ */ import_react37.default.createElement("span", null, "Max: ", max)));
13469
+ }
13470
+ NumericEditor.displayName = "NumericEditor";
13471
+
13472
+ // src/editors/MultiSelectEditor.tsx
13473
+ var import_react38 = __toESM(require("react"), 1);
13474
+ function MultiSelectEditor(props) {
13475
+ const {
13476
+ value = [],
13477
+ onChange,
13478
+ onCommit,
13479
+ onCancel,
13480
+ autoFocus = true,
13481
+ options,
13482
+ placeholder = "Select...",
13483
+ maxTagCount = 3,
13484
+ filterable = true,
13485
+ maxDropdownHeight = 300,
13486
+ allowEmpty = true
13487
+ } = props;
13488
+ const [isOpen] = (0, import_react38.useState)(true);
13489
+ const [searchQuery, setSearchQuery] = (0, import_react38.useState)("");
13490
+ const [focusedIndex, setFocusedIndex] = (0, import_react38.useState)(-1);
13491
+ const containerRef = (0, import_react38.useRef)(null);
13492
+ const inputRef = useEditorAutoFocus(autoFocus);
13493
+ const dropdownRef = (0, import_react38.useRef)(null);
13494
+ const tagContainerRef = (0, import_react38.useRef)(null);
13495
+ const selectedValues = (0, import_react38.useMemo)(
13496
+ () => Array.isArray(value) ? value : [],
13497
+ [value]
13498
+ );
13499
+ const filteredOptions = (0, import_react38.useMemo)(
13500
+ () => filterable ? filterOptions(options, searchQuery) : options,
13501
+ [options, searchQuery, filterable]
13502
+ );
13503
+ const selectedOptions = (0, import_react38.useMemo)(
13504
+ () => options.filter((opt) => selectedValues.includes(opt.value)),
13505
+ [options, selectedValues]
13506
+ );
13507
+ usePopupPosition(containerRef, dropdownRef, isOpen, "auto");
13508
+ useEditorClickOutside(
13509
+ containerRef,
13510
+ () => {
13511
+ if (isOpen) {
13512
+ onCommit();
13513
+ }
13514
+ },
13515
+ true
13516
+ );
13517
+ const handleToggleOption = (option) => {
13518
+ if (option.disabled) return;
13519
+ const isSelected = selectedValues.includes(option.value);
13520
+ let newValues;
13521
+ if (isSelected) {
13522
+ if (!allowEmpty && selectedValues.length === 1) {
13523
+ return;
13524
+ }
13525
+ newValues = selectedValues.filter((v) => v !== option.value);
13526
+ } else {
13527
+ newValues = [...selectedValues, option.value];
13528
+ }
13529
+ onChange(newValues);
13530
+ };
13531
+ const handleRemoveTag = (optionValue, e) => {
13532
+ e.stopPropagation();
13533
+ if (!allowEmpty && selectedValues.length === 1) {
13534
+ return;
13535
+ }
13536
+ const newValues = selectedValues.filter((v) => v !== optionValue);
13537
+ onChange(newValues);
13538
+ };
13539
+ const handleKeyDown = (e) => {
13540
+ if (e.key === "Backspace" && searchQuery === "" && selectedValues.length > 0) {
13541
+ e.preventDefault();
13542
+ if (allowEmpty || selectedValues.length > 1) {
13543
+ const newValues = selectedValues.slice(0, -1);
13544
+ onChange(newValues);
13545
+ }
13546
+ }
13547
+ };
13548
+ const handleArrowDown = () => {
13549
+ setFocusedIndex((prev) => {
13550
+ var _a;
13551
+ let next = prev + 1;
13552
+ while (next < filteredOptions.length && ((_a = filteredOptions[next]) == null ? void 0 : _a.disabled)) {
13553
+ next++;
13554
+ }
13555
+ return next < filteredOptions.length ? next : prev;
13556
+ });
13557
+ };
13558
+ const handleArrowUp = () => {
13559
+ setFocusedIndex((prev) => {
13560
+ var _a;
13561
+ let next = prev - 1;
13562
+ while (next >= 0 && ((_a = filteredOptions[next]) == null ? void 0 : _a.disabled)) {
13563
+ next--;
13564
+ }
13565
+ return next >= 0 ? next : prev;
13566
+ });
13567
+ };
13568
+ const handleEnter = () => {
13569
+ if (focusedIndex >= 0 && focusedIndex < filteredOptions.length) {
13570
+ const option = filteredOptions[focusedIndex];
13571
+ if (option && !option.disabled) {
13572
+ handleToggleOption(option);
13573
+ }
13574
+ } else {
13575
+ onCommit();
13576
+ }
13577
+ };
13578
+ const { handleKeyDown: handleEditorKeyDown } = useEditorKeyboardNavigation(
13579
+ {
13580
+ onEnter: handleEnter,
13581
+ onEscape: onCancel,
13582
+ onArrowUp: handleArrowUp,
13583
+ onArrowDown: handleArrowDown
13584
+ },
13585
+ {
13586
+ commitOnTab: true,
13587
+ commitOnBlur: false
13588
+ }
13589
+ );
13590
+ const handleCombinedKeyDown = (e) => {
13591
+ handleKeyDown(e);
13592
+ handleEditorKeyDown(e);
13593
+ };
13594
+ const visibleTags = selectedOptions.slice(0, maxTagCount);
13595
+ const collapsedCount = Math.max(0, selectedOptions.length - maxTagCount);
13596
+ return /* @__PURE__ */ import_react38.default.createElement(
13597
+ "div",
13598
+ {
13599
+ ref: containerRef,
13600
+ className: "editor-container editor-multiselect-container",
13601
+ onKeyDown: handleCombinedKeyDown
13602
+ },
13603
+ /* @__PURE__ */ import_react38.default.createElement(
13604
+ "div",
13605
+ {
13606
+ ref: tagContainerRef,
13607
+ className: "editor-input-wrapper editor-multiselect-wrapper"
13608
+ },
13609
+ /* @__PURE__ */ import_react38.default.createElement("div", { className: "editor-multiselect-tags" }, visibleTags.map((option) => /* @__PURE__ */ import_react38.default.createElement("div", { key: option.value, className: "editor-tag" }, option.icon && /* @__PURE__ */ import_react38.default.createElement("span", { className: "editor-tag-icon" }, option.icon), /* @__PURE__ */ import_react38.default.createElement("span", { className: "editor-tag-label" }, option.label), /* @__PURE__ */ import_react38.default.createElement(
13610
+ "button",
13611
+ {
13612
+ type: "button",
13613
+ className: "editor-tag-remove",
13614
+ onClick: (e) => handleRemoveTag(option.value, e),
13615
+ "aria-label": `Remove ${option.label}`,
13616
+ tabIndex: -1
13617
+ },
13618
+ "\xD7"
13619
+ ))), collapsedCount > 0 && /* @__PURE__ */ import_react38.default.createElement("div", { className: "editor-tag editor-tag-collapsed" }, "+", collapsedCount)),
13620
+ /* @__PURE__ */ import_react38.default.createElement(
13621
+ "input",
13622
+ {
13623
+ ref: inputRef,
13624
+ type: "text",
13625
+ className: "editor-input editor-multiselect-input",
13626
+ value: searchQuery,
13627
+ onChange: (e) => {
13628
+ setSearchQuery(e.target.value);
13629
+ setFocusedIndex(-1);
13630
+ },
13631
+ placeholder: selectedValues.length === 0 ? placeholder : "",
13632
+ "aria-label": "Search options",
13633
+ "aria-expanded": isOpen,
13634
+ "aria-autocomplete": "list",
13635
+ "aria-controls": "multiselect-dropdown",
13636
+ autoComplete: "off"
13637
+ }
13638
+ ),
13639
+ /* @__PURE__ */ import_react38.default.createElement("span", { className: "editor-dropdown-icon", "aria-hidden": "true" }, "\u25BC")
13640
+ ),
13641
+ isOpen && /* @__PURE__ */ import_react38.default.createElement(
13642
+ "div",
13643
+ {
13644
+ ref: dropdownRef,
13645
+ id: "multiselect-dropdown",
13646
+ className: "editor-dropdown",
13647
+ role: "listbox",
13648
+ "aria-multiselectable": "true",
13649
+ style: { maxHeight: maxDropdownHeight }
13650
+ },
13651
+ filteredOptions.length === 0 ? /* @__PURE__ */ import_react38.default.createElement("div", { className: "editor-dropdown-empty" }, "No options found") : filteredOptions.map((option, index) => {
13652
+ const isSelected = selectedValues.includes(option.value);
13653
+ return /* @__PURE__ */ import_react38.default.createElement(
13654
+ "div",
13655
+ {
13656
+ key: option.value,
13657
+ className: `editor-dropdown-option editor-multiselect-option ${isSelected ? "selected" : ""} ${option.disabled ? "disabled" : ""} ${index === focusedIndex ? "focused" : ""}`,
13658
+ role: "option",
13659
+ "aria-selected": isSelected,
13660
+ "aria-disabled": option.disabled,
13661
+ onClick: () => handleToggleOption(option),
13662
+ onMouseEnter: () => !option.disabled && setFocusedIndex(index)
13663
+ },
13664
+ /* @__PURE__ */ import_react38.default.createElement(
13665
+ "input",
13666
+ {
13667
+ type: "checkbox",
13668
+ className: "editor-multiselect-checkbox",
13669
+ checked: isSelected,
13670
+ onChange: () => {
13671
+ },
13672
+ disabled: option.disabled,
13673
+ tabIndex: -1,
13674
+ "aria-hidden": "true"
13675
+ }
13676
+ ),
13677
+ /* @__PURE__ */ import_react38.default.createElement("div", { className: "editor-option-content" }, option.icon && /* @__PURE__ */ import_react38.default.createElement("span", { className: "editor-option-icon" }, option.icon), /* @__PURE__ */ import_react38.default.createElement("span", { className: "editor-option-label" }, option.label))
13678
+ );
13679
+ })
13680
+ )
13681
+ );
13682
+ }
13683
+ MultiSelectEditor.displayName = "MultiSelectEditor";
13684
+
13685
+ // src/editors/MarkdownEditor.tsx
13686
+ var import_react39 = __toESM(require("react"), 1);
13687
+ function MarkdownEditor(props) {
13688
+ const {
13689
+ value = "",
13690
+ onChange,
13691
+ onCommit,
13692
+ onCancel,
13693
+ autoFocus = true,
13694
+ maxLength,
13695
+ showPreview = true,
13696
+ minHeight = 150,
13697
+ maxHeight = 400,
13698
+ rows = 6
13699
+ } = props;
13700
+ const [internalValue, setInternalValue] = (0, import_react39.useState)(value || "");
13701
+ const [showPreviewPanel, setShowPreviewPanel] = (0, import_react39.useState)(showPreview);
13702
+ const containerRef = (0, import_react39.useRef)(null);
13703
+ const textareaRef = useEditorAutoFocus(autoFocus, true);
13704
+ useEditorClickOutside(
13705
+ containerRef,
13706
+ () => {
13707
+ onCommit();
13708
+ },
13709
+ true
13710
+ );
13711
+ const handleChange = (e) => {
13712
+ const newValue = e.target.value;
13713
+ if (maxLength && newValue.length > maxLength) {
13714
+ return;
13715
+ }
13716
+ setInternalValue(newValue);
13717
+ onChange(newValue);
13718
+ };
13719
+ const handleKeyDown = (e) => {
13720
+ if ((e.ctrlKey || e.metaKey) && e.key === "Enter") {
13721
+ e.preventDefault();
13722
+ onCommit();
13723
+ return;
13724
+ }
13725
+ if (e.key === "Escape") {
13726
+ e.preventDefault();
13727
+ onCancel();
13728
+ return;
13729
+ }
13730
+ if (e.key === "Tab") {
13731
+ e.preventDefault();
13732
+ const start = e.currentTarget.selectionStart;
13733
+ const end = e.currentTarget.selectionEnd;
13734
+ const newValue = internalValue.substring(0, start) + " " + internalValue.substring(end);
13735
+ setInternalValue(newValue);
13736
+ onChange(newValue);
13737
+ setTimeout(() => {
13738
+ if (textareaRef.current) {
13739
+ textareaRef.current.selectionStart = start + 1;
13740
+ textareaRef.current.selectionEnd = start + 1;
13741
+ }
13742
+ }, 0);
13743
+ return;
13744
+ }
13745
+ if (e.ctrlKey || e.metaKey) {
13746
+ let insertion = "";
13747
+ let cursorOffset = 0;
13748
+ switch (e.key) {
13749
+ case "b":
13750
+ insertion = "****";
13751
+ cursorOffset = 2;
13752
+ break;
13753
+ case "i":
13754
+ insertion = "__";
13755
+ cursorOffset = 1;
13756
+ break;
13757
+ case "k":
13758
+ insertion = "[](url)";
13759
+ cursorOffset = 1;
13760
+ break;
13761
+ default:
13762
+ return;
13763
+ }
13764
+ if (insertion) {
13765
+ e.preventDefault();
13766
+ const start = e.currentTarget.selectionStart;
13767
+ const end = e.currentTarget.selectionEnd;
13768
+ const selectedText = internalValue.substring(start, end);
13769
+ let newValue;
13770
+ let newCursorPos;
13771
+ if (selectedText) {
13772
+ const before = insertion.substring(0, cursorOffset);
13773
+ const after = insertion.substring(cursorOffset);
13774
+ newValue = internalValue.substring(0, start) + before + selectedText + after + internalValue.substring(end);
13775
+ newCursorPos = start + before.length + selectedText.length;
13776
+ } else {
13777
+ newValue = internalValue.substring(0, start) + insertion + internalValue.substring(end);
13778
+ newCursorPos = start + cursorOffset;
13779
+ }
13780
+ setInternalValue(newValue);
13781
+ onChange(newValue);
13782
+ setTimeout(() => {
13783
+ if (textareaRef.current) {
13784
+ textareaRef.current.selectionStart = newCursorPos;
13785
+ textareaRef.current.selectionEnd = newCursorPos;
13786
+ textareaRef.current.focus();
13787
+ }
13788
+ }, 0);
13789
+ }
13790
+ }
13791
+ };
13792
+ const charCount = internalValue.length;
13793
+ const charCountClass = maxLength && charCount > maxLength * 0.9 ? "warning" : "";
13794
+ const previewHtml = (0, import_react39.useMemo)(() => {
13795
+ return renderMarkdownPreview(internalValue);
13796
+ }, [internalValue]);
13797
+ return /* @__PURE__ */ import_react39.default.createElement(
13798
+ "div",
13799
+ {
13800
+ ref: containerRef,
13801
+ className: "editor-container editor-markdown-container",
13802
+ style: { minHeight }
13803
+ },
13804
+ /* @__PURE__ */ import_react39.default.createElement("div", { className: "editor-markdown-toolbar" }, /* @__PURE__ */ import_react39.default.createElement("div", { className: "editor-markdown-toolbar-group" }, /* @__PURE__ */ import_react39.default.createElement(
13805
+ "button",
13806
+ {
13807
+ type: "button",
13808
+ className: "editor-toolbar-btn",
13809
+ onClick: () => {
13810
+ if (textareaRef.current) {
13811
+ const start = textareaRef.current.selectionStart;
13812
+ const end = textareaRef.current.selectionEnd;
13813
+ const selectedText = internalValue.substring(start, end);
13814
+ const newValue = internalValue.substring(0, start) + `**${selectedText || "bold"}**` + internalValue.substring(end);
13815
+ setInternalValue(newValue);
13816
+ onChange(newValue);
13817
+ textareaRef.current.focus();
13818
+ }
13819
+ },
13820
+ title: "Bold (Ctrl+B)",
13821
+ "aria-label": "Bold"
13822
+ },
13823
+ /* @__PURE__ */ import_react39.default.createElement("strong", null, "B")
13824
+ ), /* @__PURE__ */ import_react39.default.createElement(
13825
+ "button",
13826
+ {
13827
+ type: "button",
13828
+ className: "editor-toolbar-btn",
13829
+ onClick: () => {
13830
+ if (textareaRef.current) {
13831
+ const start = textareaRef.current.selectionStart;
13832
+ const end = textareaRef.current.selectionEnd;
13833
+ const selectedText = internalValue.substring(start, end);
13834
+ const newValue = internalValue.substring(0, start) + `_${selectedText || "italic"}_` + internalValue.substring(end);
13835
+ setInternalValue(newValue);
13836
+ onChange(newValue);
13837
+ textareaRef.current.focus();
13838
+ }
13839
+ },
13840
+ title: "Italic (Ctrl+I)",
13841
+ "aria-label": "Italic"
13842
+ },
13843
+ /* @__PURE__ */ import_react39.default.createElement("em", null, "I")
13844
+ ), /* @__PURE__ */ import_react39.default.createElement(
13845
+ "button",
13846
+ {
13847
+ type: "button",
13848
+ className: "editor-toolbar-btn",
13849
+ onClick: () => {
13850
+ if (textareaRef.current) {
13851
+ const start = textareaRef.current.selectionStart;
13852
+ const end = textareaRef.current.selectionEnd;
13853
+ const selectedText = internalValue.substring(start, end);
13854
+ const newValue = internalValue.substring(0, start) + `[${selectedText || "link text"}](url)` + internalValue.substring(end);
13855
+ setInternalValue(newValue);
13856
+ onChange(newValue);
13857
+ textareaRef.current.focus();
13858
+ }
13859
+ },
13860
+ title: "Link (Ctrl+K)",
13861
+ "aria-label": "Link"
13862
+ },
13863
+ "\u{1F517}"
13864
+ )), /* @__PURE__ */ import_react39.default.createElement("div", { className: "editor-markdown-toolbar-group" }, /* @__PURE__ */ import_react39.default.createElement(
13865
+ "button",
13866
+ {
13867
+ type: "button",
13868
+ className: `editor-toolbar-btn ${showPreviewPanel ? "active" : ""}`,
13869
+ onClick: () => setShowPreviewPanel(!showPreviewPanel),
13870
+ title: "Toggle preview",
13871
+ "aria-label": "Toggle preview",
13872
+ "aria-pressed": showPreviewPanel
13873
+ },
13874
+ "\u{1F441}"
13875
+ ))),
13876
+ /* @__PURE__ */ import_react39.default.createElement("div", { className: `editor-markdown-content ${showPreviewPanel ? "split" : ""}` }, /* @__PURE__ */ import_react39.default.createElement("div", { className: "editor-markdown-editor" }, /* @__PURE__ */ import_react39.default.createElement(
13877
+ "textarea",
13878
+ {
13879
+ ref: textareaRef,
13880
+ className: "editor-textarea editor-markdown-textarea",
13881
+ value: internalValue,
13882
+ onChange: handleChange,
13883
+ onKeyDown: handleKeyDown,
13884
+ rows,
13885
+ maxLength,
13886
+ placeholder: "Enter markdown text...",
13887
+ "aria-label": "Markdown editor",
13888
+ style: { maxHeight }
13889
+ }
13890
+ ), /* @__PURE__ */ import_react39.default.createElement("div", { className: `editor-markdown-char-count ${charCountClass}` }, charCount, maxLength && ` / ${maxLength}`)), showPreviewPanel && /* @__PURE__ */ import_react39.default.createElement("div", { className: "editor-markdown-preview" }, /* @__PURE__ */ import_react39.default.createElement("div", { className: "editor-markdown-preview-label" }, "Preview"), /* @__PURE__ */ import_react39.default.createElement(
13891
+ "div",
13892
+ {
13893
+ className: "editor-markdown-preview-content",
13894
+ dangerouslySetInnerHTML: { __html: previewHtml }
13895
+ }
13896
+ ))),
13897
+ /* @__PURE__ */ import_react39.default.createElement("div", { className: "editor-markdown-footer" }, /* @__PURE__ */ import_react39.default.createElement("div", { className: "editor-markdown-hint" }, /* @__PURE__ */ import_react39.default.createElement("kbd", null, "Ctrl+Enter"), " to save \u2022 ", /* @__PURE__ */ import_react39.default.createElement("kbd", null, "Esc"), " to cancel"), /* @__PURE__ */ import_react39.default.createElement("div", { className: "editor-markdown-actions" }, /* @__PURE__ */ import_react39.default.createElement(
13898
+ "button",
13899
+ {
13900
+ type: "button",
13901
+ className: "editor-btn editor-btn-secondary",
13902
+ onClick: onCancel
13903
+ },
13904
+ "Cancel"
13905
+ ), /* @__PURE__ */ import_react39.default.createElement(
13906
+ "button",
13907
+ {
13908
+ type: "button",
13909
+ className: "editor-btn editor-btn-primary",
13910
+ onClick: onCommit
13911
+ },
13912
+ "Save"
13913
+ )))
13914
+ );
13915
+ }
13916
+ MarkdownEditor.displayName = "MarkdownEditor";
13917
+ function renderMarkdownPreview(markdown) {
13918
+ if (!markdown) return '<p class="editor-markdown-empty">Nothing to preview</p>';
13919
+ let html = markdown;
13920
+ html = html.replace(/&/g, "&amp;").replace(/</g, "&lt;").replace(/>/g, "&gt;").replace(/"/g, "&quot;").replace(/'/g, "&#039;");
13921
+ html = html.replace(/^### (.*$)/gim, "<h3>$1</h3>");
13922
+ html = html.replace(/^## (.*$)/gim, "<h2>$1</h2>");
13923
+ html = html.replace(/^# (.*$)/gim, "<h1>$1</h1>");
13924
+ html = html.replace(/\*\*(.+?)\*\*/g, "<strong>$1</strong>");
13925
+ html = html.replace(/__(.+?)__/g, "<strong>$1</strong>");
13926
+ html = html.replace(/\*(.+?)\*/g, "<em>$1</em>");
13927
+ html = html.replace(/_(.+?)_/g, "<em>$1</em>");
13928
+ html = html.replace(/`(.+?)`/g, "<code>$1</code>");
13929
+ html = html.replace(/\[([^\]]+)\]\(([^)]+)\)/g, '<a href="$2" target="_blank" rel="noopener noreferrer">$1</a>');
13930
+ html = html.replace(/^\* (.+)$/gim, "<li>$1</li>");
13931
+ html = html.replace(/^- (.+)$/gim, "<li>$1</li>");
13932
+ html = html.replace(/(<li>.*<\/li>)/s, "<ul>$1</ul>");
13933
+ html = html.replace(/\n\n/g, "</p><p>");
13934
+ html = html.replace(/\n/g, "<br>");
13935
+ if (!html.startsWith("<h") && !html.startsWith("<ul") && !html.startsWith("<p")) {
13936
+ html = "<p>" + html + "</p>";
13937
+ }
13938
+ return html;
13939
+ }
12160
13940
  // Annotate the CommonJS export names for ESM import in node:
12161
13941
  0 && (module.exports = {
12162
13942
  AdvancedFilterBuilder,
@@ -12166,6 +13946,7 @@ function createMockFeed(config) {
12166
13946
  ColumnFilters,
12167
13947
  CurrencyCell,
12168
13948
  DataGrid,
13949
+ DateEditor,
12169
13950
  DensityToggle,
12170
13951
  ExportMenu,
12171
13952
  FacetedSearch,
@@ -12178,11 +13959,16 @@ function createMockFeed(config) {
12178
13959
  LayoutPersistenceManager,
12179
13960
  LayoutPresetsManager,
12180
13961
  LocalStorageAdapter,
13962
+ MarkdownEditor,
12181
13963
  MarketDataEngine,
12182
13964
  MarketDataGrid,
13965
+ MultiSelectEditor,
13966
+ NumericEditor,
13967
+ PivotToolbar,
12183
13968
  PriorityIndicator,
12184
13969
  ProgressBar,
12185
13970
  Rating,
13971
+ RichSelectEditor,
12186
13972
  ServerAdapter,
12187
13973
  ServerSideDataSource,
12188
13974
  StatusChip,
@@ -12192,6 +13978,7 @@ function createMockFeed(config) {
12192
13978
  VirtualScroller,
12193
13979
  WebSocketMockFeed,
12194
13980
  alpineTheme,
13981
+ buildPivot,
12195
13982
  buildTreeFromFlat,
12196
13983
  collapseAllNodes,
12197
13984
  countTreeNodes,
@@ -12201,12 +13988,17 @@ function createMockFeed(config) {
12201
13988
  createMockWebSocket,
12202
13989
  createPreset,
12203
13990
  darkTheme,
13991
+ debounce,
12204
13992
  densityConfigs,
13993
+ downloadCSV,
12205
13994
  expandAllNodes,
13995
+ exportPivotToCSV,
12206
13996
  exportToCSV,
12207
13997
  exportToXLSX,
13998
+ filterOptions,
12208
13999
  filterTree,
12209
14000
  flattenTree,
14001
+ formatNumber,
12210
14002
  generateDensityCSS,
12211
14003
  generateFilename,
12212
14004
  generatePresetId,
@@ -12224,10 +14016,15 @@ function createMockFeed(config) {
12224
14016
  isTreeNode,
12225
14017
  loadDensityMode,
12226
14018
  materialTheme,
14019
+ parseFormattedNumber,
12227
14020
  quartzTheme,
12228
14021
  saveDensityMode,
12229
14022
  themes,
12230
14023
  toggleNodeExpansion,
12231
14024
  useDensityMode,
12232
- useMarketData
14025
+ useEditorAutoFocus,
14026
+ useEditorClickOutside,
14027
+ useEditorKeyboardNavigation,
14028
+ useMarketData,
14029
+ usePopupPosition
12233
14030
  });