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