From 46908f4bd258999345676235491f8a2960f0a9b4 Mon Sep 17 00:00:00 2001
From: origami-z <5257855+origami-z@users.noreply.github.com>
Date: Tue, 8 Oct 2024 11:41:06 +0100
Subject: [PATCH] Ag grid built in cell editor support
- Fix editable-cell input padding
- Fix long text cell overflow
- Add agLargeTextCellEditor support
- Add theme support for agSelectCellEditor
- Add agRichSelectCellEditor support
- Add site doc example
- Enable enterprise feature on site
---
.changeset/ag-cell-editors.md | 12 ++
packages/ag-grid-theme/css/parts/ag-body.css | 41 +++++-
packages/ag-grid-theme/css/parts/ag-input.css | 9 ++
.../ag-grid-theme/css/parts/ag-root-var.css | 1 +
.../agProvidedCellEditorsExampleColumns.ts | 91 +++++++++++++
.../dataGridExampleDataCellEditors.ts | 93 +++++++++++++
.../src/examples/ProvidedCellEditors.tsx | 66 +++++++++
packages/ag-grid-theme/src/examples/index.ts | 1 +
.../stories/ag-grid-theme.qa.stories.tsx | 126 +++++++++++++++++-
.../stories/ag-grid-theme.stories.tsx | 1 +
.../components/ag-grid-theme/examples.mdx | 8 ++
.../ag-grid-theme/ProvidedCellEditors.tsx | 24 ++++
.../ag-grid-theme/data/cellEditorsColumn.ts | 89 +++++++++++++
.../ag-grid-theme/data/cellEditorsData.ts | 93 +++++++++++++
.../data/cellEditorsDataTypes.ts | 47 +++++++
site/src/examples/ag-grid-theme/index.ts | 1 +
.../ag-grid-theme/useAgGridHelpers.ts | 3 +-
17 files changed, 694 insertions(+), 12 deletions(-)
create mode 100644 .changeset/ag-cell-editors.md
create mode 100644 packages/ag-grid-theme/src/dependencies/agProvidedCellEditorsExampleColumns.ts
create mode 100644 packages/ag-grid-theme/src/dependencies/dataGridExampleDataCellEditors.ts
create mode 100644 packages/ag-grid-theme/src/examples/ProvidedCellEditors.tsx
create mode 100644 site/src/examples/ag-grid-theme/ProvidedCellEditors.tsx
create mode 100644 site/src/examples/ag-grid-theme/data/cellEditorsColumn.ts
create mode 100644 site/src/examples/ag-grid-theme/data/cellEditorsData.ts
create mode 100644 site/src/examples/ag-grid-theme/data/cellEditorsDataTypes.ts
diff --git a/.changeset/ag-cell-editors.md b/.changeset/ag-cell-editors.md
new file mode 100644
index 00000000000..c921aa10931
--- /dev/null
+++ b/.changeset/ag-cell-editors.md
@@ -0,0 +1,12 @@
+---
+"@salt-ds/ag-grid-theme": minor
+---
+
+- Added theme support for several built-in ag grid provided editors
+ - `agLargeTextCellEditor`
+ - `agSelectCellEditor`
+ - `agRichSelectCellEditor`
+ - `agNumberCellEditor`
+ - `agDateStringCellEditor`
+- Fixed `input` padding within `.editable-cell` during editing
+- Fixed long text overflow within `.editable-cell` when focused
diff --git a/packages/ag-grid-theme/css/parts/ag-body.css b/packages/ag-grid-theme/css/parts/ag-body.css
index 8e1215c80e9..a483415a6cb 100644
--- a/packages/ag-grid-theme/css/parts/ag-body.css
+++ b/packages/ag-grid-theme/css/parts/ag-body.css
@@ -41,6 +41,12 @@ div[class*="ag-theme-salt"] .ag-cell-inline-editing:focus-within {
/* This makes sure custom cell editor would start from no padding. Built-in ag grid editor's padding is added below. */
div[class*="ag-theme-salt"] .ag-cell-inline-editing {
padding: 0;
+ /* When styling option corner='rounded', we don't want this to be flipped between rounded and not between editing and normal state */
+ border-radius: 0;
+}
+
+div[class*="ag-theme-salt"] .ag-cell-inline-editing.editable-cell input[class^="ag-"] {
+ padding: 0 var(--salt-spacing-100);
}
div[class*="ag-theme-salt"] .editable-cell,
@@ -73,12 +79,6 @@ div[class*="ag-theme-salt"] .ag-cell-wrapper.ag-row-group {
align-items: center;
}
-div[class*="ag-theme-salt"] .ag-cell.editable-cell.ag-cell-focus:focus,
-div[class*="ag-theme-salt"] .editable-numeric-cell.ag-cell-focus:focus,
-div[class*="ag-theme-salt"] .editable-cell.ag-cell-focus:focus-within {
- overflow: visible;
-}
-
div[class*="ag-theme-salt"] .ag-cell.editable-cell.ag-cell-focus:focus:before,
div[class*="ag-theme-salt"] .ag-cell.editable-numeric-cell.ag-cell-focus:focus:before,
div[class*="ag-theme-salt"] .ag-cell.editable-cell.ag-cell-focus:focus-within:before,
@@ -105,6 +105,35 @@ div[class*="ag-theme-salt"] .editable-numeric-cell input {
background-color: transparent;
}
+/* Ag Select Cell Editor - all should be scoped with `.editable-cell` so it's not impacting users not using our class */
+
+div[class*="ag-theme-salt"] .editable-cell .ag-picker-field-wrapper {
+ /* Allow cell focus ring to come through */
+ background-color: transparent;
+ border: none;
+}
+
+div[class*="ag-theme-salt"] .ag-ltr .editable-cell .ag-select .ag-picker-field-wrapper,
+div[class*="ag-theme-salt"] .ag-ltr .editable-cell .ag-rich-select .ag-picker-field-wrapper {
+ padding: 0 var(--salt-spacing-100);
+ border-radius: 0;
+}
+
+div[class*="ag-theme-salt"] .ag-ltr .editable-cell .ag-select .ag-icon-small-down::before,
+div[class*="ag-theme-salt"] .ag-ltr .editable-cell .ag-rich-select .ag-icon-small-down::before {
+ /* Change the icon to be aligned with Salt chevron instead of triangle */
+ /* We are not using different icons between collpase / expand, given only collapsed icon is available in ag salt icon font (.ag-picker-collapsed vs .ag-picker-expanded) */
+ content: var(--ag-icon-font-code-contracted);
+}
+
+div[class*="ag-theme-salt"] .ag-ltr .ag-select-list-item,
+div[class*="ag-theme-salt"] .ag-ltr .ag-rich-select-row {
+ /* This can't be scoped to editable-cell given it's sitting within .ag-popup */
+ padding: 0 var(--salt-spacing-100);
+}
+
+/* Range selection cross cells "fake" outlines */
+
div[class*="ag-theme-salt"] .ag-cell.ag-cell-range-selected:not(.ag-cell-range-single-cell).ag-cell-range-top::after {
content: "";
top: 0;
diff --git a/packages/ag-grid-theme/css/parts/ag-input.css b/packages/ag-grid-theme/css/parts/ag-input.css
index b5be4bd0085..482746c1344 100644
--- a/packages/ag-grid-theme/css/parts/ag-input.css
+++ b/packages/ag-grid-theme/css/parts/ag-input.css
@@ -25,3 +25,12 @@ div[class*="ag-theme-salt"] .ag-column-select input[class^="ag-"][type="number"]
outline: var(--salt-focused-outlineWidth) var(--salt-focused-outlineStyle) var(--salt-focused-outlineColor);
outline-offset: -2px;
}
+
+/* Large text editor, matching multiline input */
+div[class*="ag-theme-salt"] .ag-popup-editor .ag-large-text textarea[class^="ag-"] {
+ border-radius: var(--salt-palette-corner-weak, 0);
+}
+
+div[class*="ag-theme-salt"] .ag-popup-editor .ag-large-text textarea[class^="ag-"]:focus {
+ outline: var(--salt-focused-outlineWidth) var(--salt-focused-outlineStyle) var(--salt-focused-outlineColor);
+}
diff --git a/packages/ag-grid-theme/css/parts/ag-root-var.css b/packages/ag-grid-theme/css/parts/ag-root-var.css
index acfd7aa0920..6f6a4c0a8d3 100644
--- a/packages/ag-grid-theme/css/parts/ag-root-var.css
+++ b/packages/ag-grid-theme/css/parts/ag-root-var.css
@@ -45,6 +45,7 @@ div[class*="ag-theme-salt"] {
--ag-selected-tab-underline-color: var(--salt-navigable-indicator-active);
--ag-selected-tab-underline-width: var(--salt-size-indicator);
--ag-subheader-background-color: var(--salt-container-primary-background);
+ --ag-control-panel-background-color: var(--salt-container-primary-background);
--ag-toggle-button-off-background-color: var(--salt-container-primary-background);
--ag-toggle-button-off-border-color: var(--salt-selectable-borderColor);
--ag-toggle-button-on-background-color: var(--salt-container-primary-background);
diff --git a/packages/ag-grid-theme/src/dependencies/agProvidedCellEditorsExampleColumns.ts b/packages/ag-grid-theme/src/dependencies/agProvidedCellEditorsExampleColumns.ts
new file mode 100644
index 00000000000..c50714f86d4
--- /dev/null
+++ b/packages/ag-grid-theme/src/dependencies/agProvidedCellEditorsExampleColumns.ts
@@ -0,0 +1,91 @@
+import { languages, shortColorData } from "./dataGridExampleDataCellEditors";
+
+const agProvidedCellEditorsExampleColumns = [
+ {
+ headerName: "Boolean",
+ field: "checked",
+ cellDataType: "boolean",
+ cellRenderer: "agCheckboxCellRenderer",
+ cellEditor: "agCheckboxCellEditor",
+ editable: true,
+ },
+ {
+ headerName: "Text",
+ field: "name",
+ cellEditor: "agTextCellEditor",
+ editable: true,
+ filter: true,
+ floatingFilter: true,
+ cellClass: ["editable-cell"],
+ },
+ {
+ headerName: "Large Text",
+ field: "sentence",
+ cellEditor: "agLargeTextCellEditor",
+ cellEditorPopup: true,
+ editable: true,
+ filter: true,
+ floatingFilter: true,
+ cellClass: ["editable-cell"],
+ },
+ {
+ headerName: "Select",
+ field: "lang",
+ cellEditor: "agSelectCellEditor",
+ cellEditorParams: {
+ values: languages,
+ valueListGap: 0,
+ },
+ editable: true,
+ filter: true,
+ floatingFilter: true,
+ cellClass: ["editable-cell"],
+ },
+ {
+ headerName: "Rich Select",
+ field: "color",
+ cellEditor: "agRichSelectCellEditor",
+ cellEditorParams: {
+ values: shortColorData,
+ valueListGap: 0,
+ allowTyping: true,
+ filterList: true,
+ highlightMatch: true,
+ },
+ editable: true,
+ filter: true,
+ floatingFilter: true,
+ cellClass: ["editable-cell"],
+ },
+ {
+ headerName: "Number",
+ field: "count",
+ cellEditor: "agNumberCellEditor",
+ cellEditorParams: {
+ min: 0,
+ max: 100,
+ },
+ // Right aligns header
+ type: "numericColumn",
+ editable: true,
+ filter: true,
+ floatingFilter: true,
+ cellClass: ["numeric-cell", "editable-cell"],
+ },
+ {
+ headerName: "Date",
+ field: "date",
+ cellDataType: "dateString",
+ cellEditor: "agDateStringCellEditor",
+ cellEditorParams: {
+ min: "2000-01-01",
+ max: "2019-12-31",
+ },
+ editable: true,
+ filter: true,
+ floatingFilter: true,
+ cellClass: ["editable-cell"],
+ },
+];
+
+export default agProvidedCellEditorsExampleColumns;
diff --git a/packages/ag-grid-theme/src/dependencies/dataGridExampleDataCellEditors.ts b/packages/ag-grid-theme/src/dependencies/dataGridExampleDataCellEditors.ts
new file mode 100644
index 00000000000..79660dcfc5f
--- /dev/null
+++ b/packages/ag-grid-theme/src/dependencies/dataGridExampleDataCellEditors.ts
@@ -0,0 +1,93 @@
+export const languages = [
+ "English",
+ "Spanish",
+ "French",
+ "Portuguese",
+ "(other)",
+] as const;
+export const sentences = [
+ "Lorem ipsum dolor sit amet, consectetuer adipiscing elit. Maecenas porttitor congue massa.",
+ "Fusce posuere, magna sed pulvinar ultricies, purus lectus malesuada libero, sit amet commodo magna eros quis urna.",
+ "Nunc viverra imperdiet enim. Fusce est. Vivamus a tellus.",
+ "Pellentesque habitant morbi tristique senectus et netus et malesuada fames ac turpis egestas.",
+ "Proin pharetra nonummy pede. Mauris et orci. Aenean nec lorem.",
+ "In porttitor. Donec laoreet nonummy augue.",
+ "Suspendisse dui purus, scelerisque at, vulputate vitae, pretium mattis, nunc.",
+ "Mauris eget neque at sem venenatis eleifend. Ut nonummy. Fusce aliquet pede non pede.",
+ "Suspendisse dapibus lorem pellentesque magna. Integer nulla.",
+ "Donec blandit feugiat ligula. Donec hendrerit, felis et imperdiet euismod, purus ipsum pretium metus, in lacinia nulla nisl eget sapien.",
+ "Donec ut est in lectus consequat consequat. Etiam eget dui. Aliquam erat volutpat.",
+];
+export const shortColorData = [
+ "Baby blue",
+ "Black",
+ "Blue",
+ "Brown",
+ "Green",
+ "Orange",
+ "Pink",
+ "Purple",
+ "Red",
+ "White",
+ "Yellow",
+];
+
+export const currencyList = [
+ "USD",
+ "EUR",
+ "JPY",
+ "GBP",
+ "CHF",
+ "CAD",
+ "AUD",
+ "NZD",
+ "ZAR",
+];
+
+export const dataGridExampleDataCellEditors = [
+ {
+ checked: false,
+ name: currencyList[0],
+ color: shortColorData[0],
+ lang: languages[0],
+ sentence: sentences[0],
+ count: 10,
+ date: "20/05/2009",
+ },
+ {
+ checked: false,
+ name: currencyList[1],
+ color: shortColorData[1],
+ lang: languages[1],
+ sentence: sentences[1],
+ count: 50,
+ date: "20/05/2009",
+ },
+ {
+ checked: true,
+ name: currencyList[2],
+ color: shortColorData[2],
+ lang: languages[2],
+ sentence: sentences[2],
+ count: 80,
+ date: "20/05/2009",
+ },
+ {
+ checked: false,
+ name: currencyList[3],
+ color: shortColorData[3],
+ lang: languages[3],
+ sentence: sentences[3],
+ count: 55,
+ date: "20/05/2009",
+ },
+ {
+ checked: false,
+ name: currencyList[4],
+ color: shortColorData[4],
+ lang: languages[4],
+ sentence: sentences[4],
+ count: 79,
+ date: "20/05/2009",
+ },
+] as const;
diff --git a/packages/ag-grid-theme/src/examples/ProvidedCellEditors.tsx b/packages/ag-grid-theme/src/examples/ProvidedCellEditors.tsx
new file mode 100644
index 00000000000..1c94fe644f2
--- /dev/null
+++ b/packages/ag-grid-theme/src/examples/ProvidedCellEditors.tsx
@@ -0,0 +1,66 @@
+import type {
+ ValueFormatterLiteParams,
+ ValueParserLiteParams,
+} from "ag-grid-community";
+import { AgGridReact, type AgGridReactProps } from "ag-grid-react";
+import agProvidedCellEditorsExampleColumns from "../dependencies/agProvidedCellEditorsExampleColumns";
+import { dataGridExampleDataCellEditors } from "../dependencies/dataGridExampleDataCellEditors";
+import { useAgGridHelpers } from "../dependencies/useAgGridHelpers";
+
+// https://www.ag-grid.com/javascript-data-grid/cell-data-types/#date-as-string-data-type-definition
+const dateString = {
+ baseDataType: "dateString" as const,
+ extendsDataType: "dateString" as const,
+ valueParser: (
+ params: ValueParserLiteParams<
+ (typeof dataGridExampleDataCellEditors)[number],
+ string
+ >,
+ ) =>
+ params.newValue?.match("\\d{2}/\\d{2}/\\d{4}") ? params.newValue : null,
+ valueFormatter: (
+ params: ValueFormatterLiteParams<
+ (typeof dataGridExampleDataCellEditors)[number],
+ string
+ >,
+ ) => (params.value == null ? "" : params.value),
+ dataTypeMatcher: (value: any) =>
+ typeof value === "string" && !!value.match("\\d{2}/\\d{2}/\\d{4}"),
+ dateParser: (value: string | undefined) => {
+ if (value == null || value === "") {
+ return undefined;
+ }
+ const dateParts = value.split("/");
+ return dateParts.length === 3
+ ? new Date(
+ Number.parseInt(dateParts[2]),
+ Number.parseInt(dateParts[1]) - 1,
+ Number.parseInt(dateParts[0]),
+ )
+ : undefined;
+ },
+ dateFormatter: (value: Date | undefined) => {
+ if (value == null) {
+ return undefined;
+ }
+ const date = String(value.getDate());
+ const month = String(value.getMonth() + 1);
+ return `${date.length === 1 ? `0${date}` : date}/${month.length === 1 ? `0${month}` : month}/${value.getFullYear()}`;
+ },
+};
+
+export const ProvidedCellEditors = (props: AgGridReactProps) => {
+ const { agGridProps, containerProps } = useAgGridHelpers();
+
+ return (
+
+ );
+};
diff --git a/packages/ag-grid-theme/src/examples/index.ts b/packages/ag-grid-theme/src/examples/index.ts
index 118db3e0d59..6aafd441b13 100644
--- a/packages/ag-grid-theme/src/examples/index.ts
+++ b/packages/ag-grid-theme/src/examples/index.ts
@@ -14,6 +14,7 @@ export { default as MasterDetail } from "./MasterDetail";
export { default as NoDataOverlay } from "./NoDataOverlay";
export { default as InfiniteScroll } from "./InfiniteScroll";
export { default as PinnedRows } from "./PinnedRows";
+export { ProvidedCellEditors } from "./ProvidedCellEditors";
export { RangeSelection } from "./RangeSelection";
export { default as Pagination } from "./Pagination";
export { default as ParentChildRows } from "./ParentChildRows";
diff --git a/packages/ag-grid-theme/stories/ag-grid-theme.qa.stories.tsx b/packages/ag-grid-theme/stories/ag-grid-theme.qa.stories.tsx
index ac4c410603e..1c8431f2a18 100644
--- a/packages/ag-grid-theme/stories/ag-grid-theme.qa.stories.tsx
+++ b/packages/ag-grid-theme/stories/ag-grid-theme.qa.stories.tsx
@@ -6,6 +6,7 @@ import {
ContextMenu as ContextMenuGrid,
CustomFilter,
Default,
+ ProvidedCellEditors,
ToolPanel,
} from "../src/examples";
@@ -294,6 +295,126 @@ EditableCellFocus.play = async ({ canvasElement }) => {
}
};
+export const EditableCellLongTextFocus: StoryObj = () => {
+ return ;
+};
+EditableCellLongTextFocus.play = async ({ canvasElement }) => {
+ const canvas = within(canvasElement);
+
+ // Wait until the grid fully loaded
+ await sleep(200);
+
+ // Do findAll here so this will also work in `side-by-side` mode
+ const textEditorCells = await canvas.findAllByText(/Lorem ipsum/);
+
+ for (const cell of textEditorCells) {
+ await userEvent.click(cell);
+
+ await expect(cell).toHaveClass(
+ "ag-cell-not-inline-editing",
+ "editable-cell",
+ );
+ // Tests focus style of long text, it should still be truncated
+ }
+};
+
+// Function to emulate pausing between interactions
+function sleep(ms: number) {
+ return new Promise((resolve) => setTimeout(resolve, ms));
+}
+
+export const EditableCellEditing: StoryObj = () => {
+ return ;
+};
+EditableCellEditing.play = async ({ canvasElement }) => {
+ const canvas = within(canvasElement);
+
+ // Wait until the grid fully loaded
+ await sleep(200);
+
+ // Do findAll here so this will also work in `side-by-side` mode
+ const textEditorCells = await canvas.findAllByText("USD");
+
+ for (const cell of textEditorCells) {
+ await userEvent.dblClick(cell);
+
+ await expect(cell).toHaveClass("ag-cell-inline-editing", "editable-cell");
+ await expect(await within(cell).findByRole("textbox")).toHaveClass(
+ "ag-input-field-input",
+ );
+ }
+};
+
+export const EditableCellLongTextEditing: StoryObj = () => {
+ return ;
+};
+EditableCellLongTextEditing.play = async ({ canvasElement }) => {
+ const canvas = within(canvasElement);
+
+ // Wait until the grid fully loaded
+ await sleep(200);
+
+ // Do findAll here so this will also work in `side-by-side` mode
+ const textEditorCells = await canvas.findAllByText(/Lorem ipsum/);
+
+ for (const cell of textEditorCells) {
+ await userEvent.dblClick(cell);
+
+ await expect(await canvas.findByRole("textbox")).toHaveClass(
+ "ag-input-field-input",
+ "ag-text-area-input",
+ );
+ }
+};
+
+export const EditableCellSelectEditing: StoryObj = () => {
+ return ;
+};
+EditableCellSelectEditing.play = async ({ canvasElement }) => {
+ const canvas = within(canvasElement);
+
+ // Wait until the grid fully loaded
+ await sleep(200);
+
+ // Do findAll here so this will also work in `side-by-side` mode
+ const textEditorCells = await canvas.findAllByText("English");
+
+ for (const cell of textEditorCells) {
+ await userEvent.dblClick(cell);
+ // Editor will render a different value in the editor, not the same "cell"
+ await userEvent.click(await within(cell).findByText("English"));
+
+ await expect(cell).toHaveClass("ag-cell-inline-editing", "editable-cell");
+ await expect(await canvas.findByRole("listbox")).toHaveClass(
+ "ag-select-list",
+ );
+ }
+};
+
+export const EditableCellRichSelectEditing: StoryObj<
+ typeof AgGridReact
+> = () => {
+ return ;
+};
+EditableCellRichSelectEditing.play = async ({ canvasElement }) => {
+ const canvas = within(canvasElement);
+
+ // Wait until the grid fully loaded
+ await sleep(200);
+
+ // Do findAll here so this will also work in `side-by-side` mode
+ const textEditorCells = await canvas.findAllByText("Black");
+
+ for (const cell of textEditorCells) {
+ await userEvent.dblClick(cell);
+
+ await expect(cell).toHaveClass("ag-cell-inline-editing", "editable-cell");
+ await expect(await canvas.findByRole("listbox")).toHaveClass(
+ "ag-rich-select-virtual-list-container",
+ );
+ }
+};
+
export const ContextMenu: StoryObj = () => {
return ;
};
@@ -313,11 +434,6 @@ ContextMenu.play = async ({ canvasElement }) => {
}
};
-// Function to emulate pausing between interactions
-function sleep(ms: number) {
- return new Promise((resolve) => setTimeout(resolve, ms));
-}
-
export const FloatingFilterFocus: StoryObj = () => {
return ;
};
diff --git a/packages/ag-grid-theme/stories/ag-grid-theme.stories.tsx b/packages/ag-grid-theme/stories/ag-grid-theme.stories.tsx
index d52eddce2fd..f1e3ba9bece 100644
--- a/packages/ag-grid-theme/stories/ag-grid-theme.stories.tsx
+++ b/packages/ag-grid-theme/stories/ag-grid-theme.stories.tsx
@@ -40,6 +40,7 @@ export {
Pagination,
ParentChildRows,
PinnedRows,
+ ProvidedCellEditors,
RangeSelection,
RowGroupPanel,
RowGrouping,
diff --git a/site/docs/components/ag-grid-theme/examples.mdx b/site/docs/components/ag-grid-theme/examples.mdx
index df25a6cb756..2d58ab80f23 100644
--- a/site/docs/components/ag-grid-theme/examples.mdx
+++ b/site/docs/components/ag-grid-theme/examples.mdx
@@ -31,6 +31,14 @@ The class names are:
+
+
+## Cell editors
+
+Salt provides styling for a few ag grid [built in cell editor](https://www.ag-grid.com/react-data-grid/provided-cell-editors/) types to best match Salt theme. This is only enabled when `editable-cell` is applied in `cellClass` together with corresponding `ag*CellEditor` specificed in `cellEditor`, and this won't affect your own custom cell editors.
+
+
+
## Checkbox selection
diff --git a/site/src/examples/ag-grid-theme/ProvidedCellEditors.tsx b/site/src/examples/ag-grid-theme/ProvidedCellEditors.tsx
new file mode 100644
index 00000000000..32821143c60
--- /dev/null
+++ b/site/src/examples/ag-grid-theme/ProvidedCellEditors.tsx
@@ -0,0 +1,24 @@
+import { AgGridReact, type AgGridReactProps } from "ag-grid-react";
+import { cellEditorsColumn } from "./data/cellEditorsColumn";
+// refer to https://github.com/jpmorganchase/salt-ds/tree/main/site/src/examples/ag-grid-theme/data
+import { dataGridExampleDataCellEditors } from "./data/cellEditorsData";
+import { dateString } from "./data/cellEditorsDataTypes";
+import { useAgGridHelpers } from "./useAgGridHelpers";
+
+export const ProvidedCellEditors = (props: AgGridReactProps) => {
+ // We've created a local custom hook to set the rows and column sizes.
+ // refer to https://github.com/jpmorganchase/salt-ds/blob/main/site/src/examples/ag-grid-theme/useAgGridHelpers.ts
+ const { containerProps, agGridProps } = useAgGridHelpers();
+
+ return (
+
+ );
+};
diff --git a/site/src/examples/ag-grid-theme/data/cellEditorsColumn.ts b/site/src/examples/ag-grid-theme/data/cellEditorsColumn.ts
new file mode 100644
index 00000000000..036c86793cb
--- /dev/null
+++ b/site/src/examples/ag-grid-theme/data/cellEditorsColumn.ts
@@ -0,0 +1,89 @@
+import { languages, shortColorData } from "./cellEditorsData";
+
+export const cellEditorsColumn = [
+ {
+ headerName: "Boolean",
+ field: "checked",
+ cellDataType: "boolean",
+ cellRenderer: "agCheckboxCellRenderer",
+ cellEditor: "agCheckboxCellEditor",
+ editable: true,
+ },
+ {
+ headerName: "Text",
+ field: "name",
+ cellEditor: "agTextCellEditor",
+ editable: true,
+ filter: true,
+ floatingFilter: true,
+ cellClass: ["editable-cell"],
+ },
+ {
+ headerName: "Large Text",
+ field: "sentence",
+ cellEditor: "agLargeTextCellEditor",
+ cellEditorPopup: true,
+ editable: true,
+ filter: true,
+ floatingFilter: true,
+ cellClass: ["editable-cell"],
+ },
+ {
+ headerName: "Select",
+ field: "lang",
+ cellEditor: "agSelectCellEditor",
+ cellEditorParams: {
+ values: languages,
+ valueListGap: 0,
+ },
+ editable: true,
+ filter: true,
+ floatingFilter: true,
+ cellClass: ["editable-cell"],
+ },
+ {
+ headerName: "Rich Select",
+ field: "color",
+ cellEditor: "agRichSelectCellEditor",
+ cellEditorParams: {
+ values: shortColorData,
+ valueListGap: 0,
+ allowTyping: true,
+ filterList: true,
+ highlightMatch: true,
+ },
+ editable: true,
+ filter: true,
+ floatingFilter: true,
+ cellClass: ["editable-cell"],
+ },
+ {
+ headerName: "Number",
+ field: "count",
+ cellEditor: "agNumberCellEditor",
+ cellEditorParams: {
+ min: 0,
+ max: 100,
+ },
+ // Right aligns header
+ type: "numericColumn",
+ editable: true,
+ filter: true,
+ floatingFilter: true,
+ cellClass: ["numeric-cell", "editable-cell"],
+ },
+ {
+ headerName: "Date",
+ field: "date",
+ cellDataType: "dateString",
+ cellEditor: "agDateStringCellEditor",
+ cellEditorParams: {
+ min: "2000-01-01",
+ max: "2019-12-31",
+ },
+ editable: true,
+ filter: true,
+ floatingFilter: true,
+ cellClass: ["editable-cell"],
+ },
+];
diff --git a/site/src/examples/ag-grid-theme/data/cellEditorsData.ts b/site/src/examples/ag-grid-theme/data/cellEditorsData.ts
new file mode 100644
index 00000000000..79660dcfc5f
--- /dev/null
+++ b/site/src/examples/ag-grid-theme/data/cellEditorsData.ts
@@ -0,0 +1,93 @@
+export const languages = [
+ "English",
+ "Spanish",
+ "French",
+ "Portuguese",
+ "(other)",
+] as const;
+export const sentences = [
+ "Lorem ipsum dolor sit amet, consectetuer adipiscing elit. Maecenas porttitor congue massa.",
+ "Fusce posuere, magna sed pulvinar ultricies, purus lectus malesuada libero, sit amet commodo magna eros quis urna.",
+ "Nunc viverra imperdiet enim. Fusce est. Vivamus a tellus.",
+ "Pellentesque habitant morbi tristique senectus et netus et malesuada fames ac turpis egestas.",
+ "Proin pharetra nonummy pede. Mauris et orci. Aenean nec lorem.",
+ "In porttitor. Donec laoreet nonummy augue.",
+ "Suspendisse dui purus, scelerisque at, vulputate vitae, pretium mattis, nunc.",
+ "Mauris eget neque at sem venenatis eleifend. Ut nonummy. Fusce aliquet pede non pede.",
+ "Suspendisse dapibus lorem pellentesque magna. Integer nulla.",
+ "Donec blandit feugiat ligula. Donec hendrerit, felis et imperdiet euismod, purus ipsum pretium metus, in lacinia nulla nisl eget sapien.",
+ "Donec ut est in lectus consequat consequat. Etiam eget dui. Aliquam erat volutpat.",
+];
+export const shortColorData = [
+ "Baby blue",
+ "Black",
+ "Blue",
+ "Brown",
+ "Green",
+ "Orange",
+ "Pink",
+ "Purple",
+ "Red",
+ "White",
+ "Yellow",
+];
+
+export const currencyList = [
+ "USD",
+ "EUR",
+ "JPY",
+ "GBP",
+ "CHF",
+ "CAD",
+ "AUD",
+ "NZD",
+ "ZAR",
+];
+
+export const dataGridExampleDataCellEditors = [
+ {
+ checked: false,
+ name: currencyList[0],
+ color: shortColorData[0],
+ lang: languages[0],
+ sentence: sentences[0],
+ count: 10,
+ date: "20/05/2009",
+ },
+ {
+ checked: false,
+ name: currencyList[1],
+ color: shortColorData[1],
+ lang: languages[1],
+ sentence: sentences[1],
+ count: 50,
+ date: "20/05/2009",
+ },
+ {
+ checked: true,
+ name: currencyList[2],
+ color: shortColorData[2],
+ lang: languages[2],
+ sentence: sentences[2],
+ count: 80,
+ date: "20/05/2009",
+ },
+ {
+ checked: false,
+ name: currencyList[3],
+ color: shortColorData[3],
+ lang: languages[3],
+ sentence: sentences[3],
+ count: 55,
+ date: "20/05/2009",
+ },
+ {
+ checked: false,
+ name: currencyList[4],
+ color: shortColorData[4],
+ lang: languages[4],
+ sentence: sentences[4],
+ count: 79,
+ date: "20/05/2009",
+ },
+] as const;
diff --git a/site/src/examples/ag-grid-theme/data/cellEditorsDataTypes.ts b/site/src/examples/ag-grid-theme/data/cellEditorsDataTypes.ts
new file mode 100644
index 00000000000..6e367ab80c2
--- /dev/null
+++ b/site/src/examples/ag-grid-theme/data/cellEditorsDataTypes.ts
@@ -0,0 +1,47 @@
+import type {
+ ValueFormatterLiteParams,
+ ValueParserLiteParams,
+} from "ag-grid-community";
+import type { dataGridExampleDataCellEditors } from "./cellEditorsData";
+
+// https://www.ag-grid.com/javascript-data-grid/cell-data-types/#date-as-string-data-type-definition
+export const dateString = {
+ baseDataType: "dateString" as const,
+ extendsDataType: "dateString" as const,
+ valueParser: (
+ params: ValueParserLiteParams<
+ (typeof dataGridExampleDataCellEditors)[number],
+ string
+ >,
+ ) =>
+ params.newValue?.match("\\d{2}/\\d{2}/\\d{4}") ? params.newValue : null,
+ valueFormatter: (
+ params: ValueFormatterLiteParams<
+ (typeof dataGridExampleDataCellEditors)[number],
+ string
+ >,
+ ) => (params.value == null ? "" : params.value),
+ dataTypeMatcher: (value: any) =>
+ typeof value === "string" && !!value.match("\\d{2}/\\d{2}/\\d{4}"),
+ dateParser: (value: string | undefined) => {
+ if (value == null || value === "") {
+ return undefined;
+ }
+ const dateParts = value.split("/");
+ return dateParts.length === 3
+ ? new Date(
+ Number.parseInt(dateParts[2]),
+ Number.parseInt(dateParts[1]) - 1,
+ Number.parseInt(dateParts[0]),
+ )
+ : undefined;
+ },
+ dateFormatter: (value: Date | undefined) => {
+ if (value == null) {
+ return undefined;
+ }
+ const date = String(value.getDate());
+ const month = String(value.getMonth() + 1);
+ return `${date.length === 1 ? `0${date}` : date}/${month.length === 1 ? `0${month}` : month}/${value.getFullYear()}`;
+ },
+};
diff --git a/site/src/examples/ag-grid-theme/index.ts b/site/src/examples/ag-grid-theme/index.ts
index 5eba87e8f03..205b2fa0501 100644
--- a/site/src/examples/ag-grid-theme/index.ts
+++ b/site/src/examples/ag-grid-theme/index.ts
@@ -15,6 +15,7 @@ export * from "./NoDataOverlay";
export * from "./Pagination";
export * from "./ParentChildRows";
export * from "./PinnedRows";
+export * from "./ProvidedCellEditors";
export * from "./RowGrouping";
export * from "./RowGroupPanel";
export * from "./StatusBar";
diff --git a/site/src/examples/ag-grid-theme/useAgGridHelpers.ts b/site/src/examples/ag-grid-theme/useAgGridHelpers.ts
index 2345ef14259..f5615f63c54 100644
--- a/site/src/examples/ag-grid-theme/useAgGridHelpers.ts
+++ b/site/src/examples/ag-grid-theme/useAgGridHelpers.ts
@@ -3,7 +3,8 @@ import type { GridApi, GridReadyEvent } from "ag-grid-community";
import { LicenseManager } from "ag-grid-enterprise";
import type { AgGridReactProps } from "ag-grid-react";
import { type HTMLAttributes, useMemo, useRef, useState } from "react";
-
+// Import enterprise to showcase theme, make sure to buy your enterprise license if needed
+import "ag-grid-enterprise";
LicenseManager.setLicenseKey("your license key");
// Helps to set className, rowHeight and headerHeight depending on the current density