From dbf724a3a8b3b1100add9eb3077562debff16bde Mon Sep 17 00:00:00 2001 From: Jordan Marr Date: Sun, 21 Apr 2024 16:28:40 -0400 Subject: [PATCH 01/27] Added some features from the enterprise version --- src/AgGrid.fs | 316 ++++++++++++++++++++++++++++++++++++++++++++------ 1 file changed, 281 insertions(+), 35 deletions(-) diff --git a/src/AgGrid.fs b/src/AgGrid.fs index eb71e85..ffb9a81 100644 --- a/src/AgGrid.fs +++ b/src/AgGrid.fs @@ -4,18 +4,200 @@ module Feliz.AgGrid open System open Fable.Core open Fable.Core.JsInterop - open Feliz let agGrid : obj = import "AgGridReact" "ag-grid-react" -importAll "ag-grid-community/styles/ag-grid.css" -importAll "ag-grid-community/styles/ag-theme-alpine.css" -importAll "ag-grid-community/styles/ag-theme-balham.css" -importAll "ag-grid-community/styles/ag-theme-material.css" +// User should load the CSS files in their own project +//importAll "ag-grid-community/styles/ag-grid.css" +//importAll "ag-grid-community/styles/ag-theme-alpine.css" +//importAll "ag-grid-community/styles/ag-theme-balham.css" +//importAll "ag-grid-community/styles/ag-theme-material.css" + +// https://www.ag-grid.com/javascript-data-grid/row-object/ +[] +type IRowNode<'row> = { + id: string + data : 'row + updateData: 'row -> unit + setData: 'row -> unit + setSelected : bool -> unit + rowIndex : int + rowTop : int + displayed : bool + isHovered : bool + isFullWidthCell : bool + isSelected : bool +} + +[] +type ICellRange = { + id : string + startRow : obj + endRow : obj +} + with + member this.startRowIndex : int = this.startRow?rowIndex + member this.endRowIndex : int = this.endRow?rowIndex + +// https://www.ag-grid.com/javascript-data-grid/grid-interface/#grid-api +[] +type IGridApi<'row> = + abstract copyToClipboard : unit -> unit + abstract pasteFromClipboard : unit -> unit + abstract refreshCells : unit -> unit + abstract redrawRows : unit -> unit + abstract setGridOption : string -> obj -> unit + abstract getSelectedNodes : unit -> IRowNode<'row>[] + abstract getCellRanges : unit -> ICellRange[] + +// https://www.ag-grid.com/javascript-data-grid/column-object/ +[] +type IColumn = { + getColId : unit -> string +} + +[] +type IColumnDefProp<'row, 'value> = interface end +let columnDefProp<'row, 'value> = unbox> + +[] +type IColumnDef<'row> = interface end + +[] +module CallbackParams = + // https://www.ag-grid.com/react-data-grid/column-properties/#reference-editing-valueSetter + // https://www.ag-grid.com/javascript-data-grid//column-properties/#reference-editing-valueParser + [] + type IValueChangedParams<'row, 'value> = { + oldValue : 'value + newValue : 'value + node : IRowNode<'row> + data : 'row + column : IColumn + colDef: IColumnDef<'row> + api : IGridApi<'row> + } + with member this.rowIndex = this.node.rowIndex + + // https://www.ag-grid.com/javascript-data-grid/component-cell-editor/#reference-ICellEditorParams + [] + type IValueParams<'row, 'value> = { + value : 'value + data : 'row + node : IRowNode<'row> + colDef : IColumnDef<'row> + column : IColumn + api : IGridApi<'row> + rowIndex: int + } + + // https://www.ag-grid.com/javascript-data-grid/grid-events/#reference-selection-cellFocused + [] + type ICellFocusedEvent<'row> = { + api : IGridApi<'row> + rowIndex : int + column : IColumn + isFullWidthCell: bool + } + + // https://www.ag-grid.com/javascript-data-grid//grid-options/#reference-rowModels-getRowId + [] + type IGetRowIdParams<'row> = { + data : 'row + level : int + parentKeys: string[] + api : IGridApi<'row> + context: obj + } + + [] + type ICellRendererParams<'row, 'value> = { + value : 'value + data : 'row + node : IRowNode<'row> + colDef : IColumnDef<'row> + column : IColumn + api : IGridApi<'row> + rowIndex: int + } + + [] + type IPasteEvent<'row> = { + source : string + api : IGridApi<'row> + context : obj + ``type`` : string + } + + [] + type IProcessDataFromClipboardParams<'row> = { + data : string[][] + api : IGridApi<'row> + context : obj + } type RowSelection = Single | Multiple -type RowFilter = Number | Text | Date member this.FilterText = sprintf "ag%OColumnFilter" this + +[] +type RowGroupingDisplayType = + | SingleColumn + | MultipleColumns + | GroupRows + | Custom + member this.RowGroupingDisplayTypeText = + match this with + | SingleColumn -> "singleColumn" + | MultipleColumns -> "multipleColumns" + | GroupRows -> "groupRows" + | Custom -> "custom" + +[] +type RowGroupPanelShow = + | Always | OnlyWhenGrouping | Never + member this.RowGroupPanelShowText = + match this with + | Always -> "always" + | OnlyWhenGrouping -> "onlyWhenGrouping" + | Never -> "never" + +[] +type RowFilter = + | Number | Text | Date | Set + member this.FilterText = sprintf "ag%OColumnFilter" this + +[] +type CellDataType = + | Text | Number | Date | DateString | Boolean | Object | Custom of string + member this.CellDataTypeText = + match this with + | Text -> "text" + | Number -> "number" + | Date -> "date" + | DateString -> "dateString" + | Boolean -> "boolean" + | Object -> "object" + | Custom s -> s + +[] +type AgCellEditor = + | SelectCellEditor + | RichSelectCellEditor + | NumberCellEditor + | DateCellEditor + | DateStringCellEditor + | CheckboxCellEditor + | LargeTextCellEditor + | TextCellEditor + member this.RichCellEditorText = + sprintf "ag%O" this + +[] + +type AggregateFunction = + | Sum | Min | Max | Count | Avg | First | Last + member this.AggregateText = (sprintf "%O" this).ToLower() + type DOMLayout = Normal | AutoHeight | Print member this.LayoutText = @@ -41,57 +223,93 @@ type MenuItem = | BuiltIn of string | Custom of MenuItemDef -[] -type IColumnDefProp<'row, 'value> = interface end -let columnDefProp<'row, 'value> = unbox> -let columnDefProps<'row, 'value> = unbox> - -[] -type IColumnDef<'row> = interface end - type ColumnType = RightAligned | NumericColumn let openClosed = function | true -> "open" | false -> "closed" [] -let CellRendererComponent<'value,'row> (render:'value -> 'row -> ReactElement, p) = - render p?value p?data +let CellRendererComponent<'row, 'value> (render: (ICellRendererParams<'row, 'value>) -> ReactElement, p: ICellRendererParams<'row, 'value>) = + render p [] type ColumnDef<'row, 'value> = + static member inline create (props: IColumnDefProp<'row, 'value> seq) = createObj !!props :?> IColumnDef<'row> + + static member inline aggFunc (v:AggregateFunction) = columnDefProp<'row, 'value> ("aggFunc" ==> v.AggregateText) static member inline autoComparator = columnDefProp<'row, 'value> ("comparator" ==> compare) static member inline cellClass (setClass:'value -> 'row -> #seq) = columnDefProp<'row, 'value> ("cellClass" ==> fun p -> setClass p?value p?data |> Seq.toArray) static member inline cellClassRules (rules: (string*('value -> 'row -> bool)) list) = columnDefProp<'row, 'value> ("cellClassRules" ==> (rules |> List.map (fun (className, rule) -> className ==> fun p -> rule p?value p?data) |> createObj)) + static member cellDataType (v:bool) = columnDefProp<'row, 'value> ("cellDataType" ==> v) + static member cellDataType (v:CellDataType) = columnDefProp<'row, 'value> ("cellDataType" ==> v.CellDataTypeText) + [] static member cellRendererFramework _ = failwith "cellRendererFramework isn't supported in the latest version of AgGrid. Use cellRenderer instead" - static member cellRenderer (render:'value -> 'row -> ReactElement) = columnDefProp<'row, 'value> ("cellRenderer" ==> fun p -> CellRendererComponent(render, p)) + + // Removed to resolve type inference issue with multiple overloads + //static member cellRenderer' (render: 'value -> 'row -> ReactElement) = columnDefProp<'row, 'value> ("cellRenderer" ==> fun (p: ICellRendererParams<'row, 'value>) -> CellRendererComponentSimple(render, p.value, p.data)) + static member cellRenderer (render: ICellRendererParams<'row, 'value> -> ReactElement) = columnDefProp<'row, 'value> ("cellRenderer" ==> fun p -> CellRendererComponent(render, p)) + + // Removed to resolve type inference issue with multiple overloads + //static member cellEditor' (render: 'value -> 'row -> ReactElement) = columnDefProp<'row, 'value> ("cellEditor" ==> fun (p: ICellRendererParams<'row, 'value>) -> CellRendererComponentSimple(render, p.value, p.data)) + static member cellEditor (render: ICellRendererParams<'row, 'value> -> ReactElement) = columnDefProp<'row, 'value> ("cellEditor" ==> fun p -> CellRendererComponent(render, p)) + static member cellEditor (v:string) = columnDefProp<'row, 'value> ("cellEditor" ==> v) + static member cellEditor (v: AgCellEditor) = columnDefProp<'row, 'value> ("cellEditor" ==> v.RichCellEditorText) + + static member cellEditorParams (v: string seq) = columnDefProp<'row, 'value> ("cellEditorParams" ==> {| values = v |> Seq.toArray |}) + static member cellEditorParams (v: obj) = columnDefProp<'row, 'value> ("cellEditorParams" ==> v) + static member cellEditorPopup (v:bool) = columnDefProp<'row, 'value> ("cellEditorPopup" ==> v) static member inline cellStyle (setStyle:'value -> 'row -> _) = columnDefProp<'row, 'value> ("cellStyle" ==> fun p -> setStyle p?value p?data) static member inline checkboxSelection (v:bool) = columnDefProp<'row, 'value> ("checkboxSelection" ==> v) static member inline colId (v:string) = columnDefProp<'row, 'value> ("colId" ==> v) static member inline columnGroupShow (v:bool) = columnDefProp<'row, 'value> ("columnGroupShow" ==> openClosed v) static member inline columnType ct = columnDefProp<'row, 'value> ("type" ==> match ct with RightAligned -> "rightAligned" | NumericColumn -> "numericColumn") static member inline comparator (callback: 'a -> 'a -> int) = columnDefProp<'row, 'value> ("comparator" ==> fun a b -> callback a b) - static member inline create<'v> (props:seq>) = props |> unbox<_ seq> |> createObj |> unbox> + static member inline editable (callback:'value -> 'row -> bool) = columnDefProp<'row, 'value> ("editable" ==> fun p -> callback p?value p?data) - static member inline field (v:'a -> string) = columnDefProp<'row, 'value> ("field" ==> v (unbox null)) - static member inline field (v:string) = columnDefProp<'row, 'value> ("field" ==> v) + static member inline editable (v: bool) = columnDefProp<'row, 'value> ("editable" ==> v) + static member inline equals (callback: 'value -> 'value -> bool) = columnDefProp<'row, 'value> ("equals" ==> callback) + static member inline enableRowGroup (v:bool) = columnDefProp<'row, 'value> ("enableRowGroup" ==> v) + static member inline enableCellChangeFlash (v:bool) = columnDefProp<'row, 'value> ("enableCellChangeFlash" ==> v) + //static member inline field (v:'a -> string) = columnDefProp<'row, 'value> ("field" ==> v (unbox null)) + static member inline field (v:string) = columnDefProp<'row, 'value> ("field" ==> v) + static member inline field (f: 'row -> _) = + // usage: `AgGrid.field _.FirstName` or `AgGrid.field (fun x -> x.FirstName)` + // Result = "FirstName" + // Get everthing after first '.' + let idxOfFirstDot = (string f).IndexOf('.') + let field = (string f).Substring(idxOfFirstDot + 1) + columnDefProp<'row, 'value> ("field" ==> field) + static member inline filter (v:RowFilter) = columnDefProp<'row, 'value> ("filter" ==> v.FilterText) + static member inline filter (v:bool) = columnDefProp<'row, 'value> ("filter" ==> v) + static member inline floatingFilter (v:bool) = columnDefProp<'row, 'value> ("floatingFilter" ==> v) static member inline headerCheckboxSelection (v:bool) = columnDefProp<'row, 'value> ("headerCheckboxSelection" ==> v) static member inline headerClass (v:string) = columnDefProp<'row, 'value> ("headerClass" ==> v) static member inline headerComponentFramework (callback:'colId -> 'props -> ReactElement) = columnDefProp<'row, 'value> ("headerComponentFramework" ==> fun p -> callback p?column?colId p) - static member inline headerName (v:string) = columnDefProp<'row, 'value> ("headerName" ==> v) + static member inline headerName (v:string) = columnDefProp<'row, 'value> ("headerName" ==> v) + static member inline wrapHeaderText (v:bool) = columnDefProp<'row, 'value> ("wrapHeaderText" ==> v) + static member inline autoHeaderHeight (v:bool) = columnDefProp<'row, 'value> ("autoHeight" ==> v) static member inline hide (v:bool) = columnDefProp<'row, 'value> ("hide" ==> v) static member inline maxWidth (v:int) = columnDefProp<'row, 'value> ("maxWidth" ==> v) static member inline minWidth (v:int) = columnDefProp<'row, 'value> ("minWidth" ==> v) static member inline onCellClicked (handler:'value -> 'row -> unit) = columnDefProp<'row, 'value> ("onCellClicked" ==> (fun p -> handler p?value p?data)) + static member inline pinned (v:bool) = columnDefProp<'row, 'value> ("pinned" ==> v) + static member inline pivot(v:bool) = columnDefProp<'row, 'value> ("pivot" ==> v) static member inline resizable (v:bool) = columnDefProp<'row, 'value> ("resizable" ==> v) + static member inline rowDrag (v:bool) = columnDefProp<'row, 'value> ("rowDrag" ==> v) + static member inline rowGroup (v:bool) = columnDefProp<'row, 'value> ("rowGroup" ==> v) static member inline sortable (v:bool) = columnDefProp<'row, 'value> ("sortable" ==> v) static member inline suppressKeyboardEvent callback = columnDefProp<'row, 'value> ("suppressKeyboardEvent" ==> fun x -> callback x?event) static member inline suppressMovable = columnDefProp<'row, 'value> ("suppressMovable" ==> true) - static member inline valueFormatter (v:'value -> 'row -> string) = columnDefProp<'row, 'value> ("valueFormatter" ==> (fun p -> v p?value p?data)) - static member inline valueGetter (f:'row -> 'value) = columnDefProp<'row, 'value> ("valueGetter" ==> (fun x -> f x?data)) - static member inline valueSetter (f:string -> 'value -> 'row -> unit) = columnDefProp<'row, 'value> ("valueSetter" ==> (fun x -> f x?newValue x?oldValue x?data; false)) // return false to prevent the grid from immediately refreshing + + // Removed to resolve type inference issue with multiple overloads + //static member inline valueFormatter (callback:'value -> 'row -> string) = columnDefProp<'row, 'value> ("valueFormatter" ==> (fun (p: IValueParams<'row, 'value>) -> callback p.value p.data)) + static member inline valueFormatter (callback: IValueParams<'row, 'value> -> string) = columnDefProp<'row, 'value> ("valueFormatter" ==> callback) + static member inline valueGetter (f:'row -> _) = columnDefProp<'row, 'value> ("valueGetter" ==> (fun x -> f x?data)) + static member inline valueSetter (f: IValueChangedParams<'row, 'value> -> unit) = columnDefProp<'row, 'value> ("valueSetter" ==> f) + static member inline valueSetter (f: IValueChangedParams<'row, 'value> -> bool) = columnDefProp<'row, 'value> ("valueSetter" ==> f) + static member inline valueParser (f: IValueChangedParams<'row, 'value> -> obj) = columnDefProp<'row, 'value> ("valueParser" ==> f) // Is never called by AgGrid static member inline width (v:int) = columnDefProp<'row, 'value> ("width" ==> v) [] @@ -104,7 +322,7 @@ type ColumnGroup<'row> = static member inline marryChildren(v:bool) = columnGroupDefProp<'row> ("marryChildren" ==> v) static member inline openByDefault(v:bool) = columnGroupDefProp<'row> ("openByDefault" ==> v) - static member inline create<'row> (props:seq>) (children:seq>) = + static member inline create (props:seq>) (children:seq>) = props |> Seq.append [(columnGroupDefProp<'row> ("children" ==> Seq.toArray children))] |> unbox<_ seq> |> createObj |> unbox> [] @@ -112,23 +330,35 @@ type IAgGridProp<'row> = interface end let agGridProp<'row> (x:obj) = unbox> x [] -type AgGrid() = - static member inline onSelectionChanged (callback:'row array -> unit) = agGridProp<'row>("onSelectionChanged", fun x -> x?api?getSelectedRows() |> callback) +type AgGrid<'row> = + static member inline animateRows (v:bool) = agGridProp<'row>("animateRows" ==> v) + static member inline alwaysShowVerticalScroll (v:bool) = agGridProp<'row>("alwaysShowVerticalScroll" ==> v) + static member inline columnDefs (columns:IColumnDef<'row> seq) = agGridProp<'row>("columnDefs", columns |> unbox |> Seq.toArray) + static member inline copyHeadersToClipboard (v:bool) = agGridProp<'row>("copyHeadersToClipboard" ==> v) + static member inline domLayout (l:DOMLayout) = agGridProp<'row>("domLayout", l.LayoutText) + static member inline enableCellTextSelection (v:bool) = agGridProp<'row> ("enableCellTextSelection" ==> v) + static member inline ensureDomOrder (v:bool) = agGridProp<'row> ("ensureDomOrder" ==> v) + static member inline enterNavigatesVertically (v:bool) = agGridProp<'row> ("enterNavigatesVertically" ==> v) + static member inline getRowNodeId (callback: 'row -> _) = agGridProp<'row>("getRowNodeId", callback) + static member inline getRowId (callback: IGetRowIdParams<'row> -> string) = agGridProp<'row>("getRowId", callback) + static member inline onCellEditRequest (callback: obj -> unit) = agGridProp<'row>("onCellEditRequest", callback) static member inline onCellValueChanged callback = agGridProp<'row>("onCellValueChanged", fun x -> callback x?data) + static member inline onPasteStart (callback: IPasteEvent<'row> -> unit) = agGridProp<'row>("onPasteStart", callback) + static member inline onPasteEnd (callback: IPasteEvent<'row> -> unit) = agGridProp<'row>("onPasteEnd", callback) static member inline onRowClicked (handler:'value -> 'row -> unit) = agGridProp<'row> ("onRowClicked" ==> (fun p -> handler p?value p?data)) + static member inline onSelectionChanged (callback:'row array -> unit) = agGridProp<'row>("onSelectionChanged", fun x -> x?api?getSelectedRows() |> callback) + static member inline readOnlyEdit (v:bool) = agGridProp<'row>("readOnlyEdit" ==> v) static member inline singleClickEdit (v:bool) = agGridProp<'row>("singleClickEdit" ==> v) static member inline rowDeselection (v:bool) = agGridProp<'row>("rowDeselection", v) static member inline rowSelection (s:RowSelection) = agGridProp<'row>("rowSelection", s.ToString().ToLower()) static member inline isRowSelectable (callback:'row -> bool) = agGridProp<'row>("isRowSelectable" ==> fun x -> x?data |> callback) static member inline suppressRowClickSelection (v:bool) = agGridProp<'row>("suppressRowClickSelection" ==> v) - static member inline enableCellTextSelection (v:bool) = agGridProp<'row> ("enableCellTextSelection" ==> v) - static member inline ensureDomOrder (v:bool) = agGridProp<'row> ("ensureDomOrder" ==> v) static member inline rowHeight (h:int) = agGridProp<'row>("rowHeight", h) - static member inline domLayout (l:DOMLayout) = agGridProp<'row>("domLayout", l.LayoutText) static member inline immutableData (v:bool) = agGridProp<'row>("immutableData", v) + /// Converts your data to a JS array to populate the grid. (This is less efficient than passing an array.) + static member inline rowData (data:'row seq) = agGridProp<'row>("rowData", Seq.toArray data) static member inline rowData (data:'row array) = agGridProp<'row>("rowData", data) - static member inline getRowNodeId (callback: 'row -> _) = agGridProp<'row>("getRowNodeId", callback) - static member inline columnDefs (columns:IColumnDef<'row> seq) = agGridProp<'row>("columnDefs", columns |> unbox |> Seq.toArray) + static member inline rowDragManaged (v:bool) = agGridProp<'row>("rowDragManaged" ==> v) static member inline defaultColDef (defaults:IColumnDefProp<'row, 'value> seq) = agGridProp<'row>("defaultColDef", defaults |> unbox<_ seq> |> createObj) static member onColumnGroupOpened (callback:_ -> unit) = // This can't be inline otherwise Fable produces invalid JS let onColumnGroupOpened = fun ev -> @@ -140,7 +370,7 @@ type AgGrid() = ev?columnApi?autoSizeColumns(colIds)) 0 |> ignore |} |> callback agGridProp<'row>("onColumnGroupOpened", onColumnGroupOpened) - + static member inline paginationPageSize (pageSize:int) = agGridProp<'row>("paginationPageSize", pageSize) static member inline paginationAutoPageSize (v:bool) = agGridProp<'row>("paginationAutoPageSize", v) static member inline pagination (v:bool) = agGridProp<'row>("pagination", v) @@ -156,8 +386,13 @@ type AgGrid() = Export = fun () -> ev?api?exportDataAsCsv(obj()) |} |> callback agGridProp<'row>("onGridReady", onGridReady) + + static member inline processDataFromClipboard (callback: IProcessDataFromClipboardParams<'row> -> string[][]) = agGridProp<'row>("processDataFromClipboard", callback) static member inline enableRangeHandle (v: bool) = agGridProp<'row>("enableRangeHandle", v) static member inline enableRangeSelection (v: bool) = agGridProp<'row>("enableRangeSelection", v) + static member inline pivotMode (v: bool) = agGridProp<'row>("pivotMode", v) + static member inline treeData (v: bool) = agGridProp<'row>("treeData", v) + static member inline suppressAggFuncInHeader (v: bool) = agGridProp<'row>("suppressAggFuncInHeader", v) static member inline getContextMenuItems (callback : int -> int -> MenuItem list) = agGridProp<'row>("getContextMenuItems", fun x -> let menuItems = callback x?node?rowIndex x?column?colId [| @@ -167,7 +402,10 @@ type AgGrid() = | Custom customMenuItem -> box customMenuItem |]) static member inline headerHeight height = agGridProp<'row>("headerHeight", height) - static member inline onCellFocused callback = agGridProp<'row>("onCellFocused", fun x -> callback x?rowIndex x?column?colId) + static member inline groupHeaderHeight height = agGridProp<'row>("groupHeaderHeight", height) + [] + static member inline onCellFocused callback = agGridProp<'row>("onCellFocused", fun x -> callback (int x?rowIndex) (int x?column?colId)) + static member inline onCellFocused callback = agGridProp<'row>("onCellFocused", fun (e: ICellFocusedEvent<'row>) -> callback e) static member inline onRangeSelectionChanged callback = agGridProp<'row>("onRangeSelectionChanged", fun x -> let selectedRange = x?api?getCellRanges()?at(0) let startRow = selectedRange?startRow?rowIndex @@ -191,4 +429,12 @@ type AgGrid() = static member inline key (v:int) = agGridProp<'row> (prop.key v) static member inline key (v:System.Guid) = agGridProp<'row> (prop.key v) - static member inline grid<'row> (props:IAgGridProp<'row> seq) = Interop.reactApi.createElement (agGrid, createObj !!props) + static member inline dataTypeDefinitions (v: obj) = agGridProp<'row>("dataTypeDefinitions", v) + static member inline enableFillHandle (v: bool) = agGridProp<'row>("enableFillHandle", v) + static member inline rowGroupPanelShow (v: RowGroupPanelShow) = agGridProp<'row>("rowGroupPanelShow", v.RowGroupPanelShowText) + static member inline groupDisplayType (v: RowGroupingDisplayType) = agGridProp<'row>("groupDisplayType", v.RowGroupingDisplayTypeText) + + static member inline undoRedoCellEditing (v: bool) = agGridProp<'row>("undoRedoCellEditing", v) + static member inline undoRedoCellEditingLimit (v: int) = agGridProp<'row>("undoRedoCellEditingLimit", v) + + static member inline grid (props: IAgGridProp<'row> seq) = Interop.reactApi.createElement (agGrid, createObj !!props) From 92c1f34e45805e37022117a61d59519d023fb98d Mon Sep 17 00:00:00 2001 From: Matt Gallagher Date: Fri, 24 May 2024 11:13:28 +0100 Subject: [PATCH 02/27] Update dependency table --- README.md | 17 +++++++++++------ 1 file changed, 11 insertions(+), 6 deletions(-) diff --git a/README.md b/README.md index 0a144ff..59dabc8 100644 --- a/README.md +++ b/README.md @@ -2,14 +2,19 @@ Feliz-style bindings for [ag-grid-react](https://www.npmjs.com/package/ag-grid-react) -## Version Compatibility +## Versions + +### Required versions of dependencies + +Note: ag-grid-react/enterprise is only required if using enterprise features. + +| Feliz.AgGrid | ag-grid-react/community | ag-grid-react/enterprise | React | Fable | Feliz | +|- |- | - |- |- |- | +| 2.x | 31.x | 31.x | 18.x | 4.x | 2.x | +| 1.x | 31.x | - | 18.x | 4.x | 2.x | +| 0.0.6 | 25.x | - | 17.x | 3.x | 1.x | -### The table below gives the ranges of compatible versions of Feliz AgGrid with its dependent packages. -| Feliz.AgGrid | ag-grid-react/community | React | Fable | Feliz | -|- |- |- |- |- | -| 0.0.6 | 25.x | 17.x | 3.x | 1.x | -| 1.x | 31.x | 18.x | 4.x | 2.x | ## Installation From ef9b6773db0998b9793857dfb120480eecfc6fd0 Mon Sep 17 00:00:00 2001 From: Matt Gallagher Date: Fri, 24 May 2024 11:17:14 +0100 Subject: [PATCH 03/27] Add CSS imports to v2 migration guide --- README.md | 11 +++++++++++ src/AgGrid.fs | 48 +++++++++++++++++++++--------------------------- 2 files changed, 32 insertions(+), 27 deletions(-) diff --git a/README.md b/README.md index 59dabc8..bbd87f3 100644 --- a/README.md +++ b/README.md @@ -14,7 +14,18 @@ Note: ag-grid-react/enterprise is only required if using enterprise features. | 1.x | 31.x | - | 18.x | 4.x | 2.x | | 0.0.6 | 25.x | - | 17.x | 3.x | 1.x | +### Migration guides +#### v1 to v2 + +To give you better control of your bundle, Feliz.AgGrid no longer imports styles for you, so you will need to include +appropriate imports yourself. For example, add the following lines to your client code to import the necessary styles +and the Balham theme. + +```fsharp +importAll "ag-grid-community/styles/ag-grid.css" +importAll "ag-grid-community/styles/ag-theme-balham.css" +``` ## Installation diff --git a/src/AgGrid.fs b/src/AgGrid.fs index ffb9a81..42753e4 100644 --- a/src/AgGrid.fs +++ b/src/AgGrid.fs @@ -8,12 +8,6 @@ open Feliz let agGrid : obj = import "AgGridReact" "ag-grid-react" -// User should load the CSS files in their own project -//importAll "ag-grid-community/styles/ag-grid.css" -//importAll "ag-grid-community/styles/ag-theme-alpine.css" -//importAll "ag-grid-community/styles/ag-theme-balham.css" -//importAll "ag-grid-community/styles/ag-theme-material.css" - // https://www.ag-grid.com/javascript-data-grid/row-object/ [] type IRowNode<'row> = { @@ -36,7 +30,7 @@ type ICellRange = { startRow : obj endRow : obj } - with + with member this.startRowIndex : int = this.startRow?rowIndex member this.endRowIndex : int = this.endRow?rowIndex @@ -65,7 +59,7 @@ let columnDefProp<'row, 'value> = unbox> type IColumnDef<'row> = interface end [] -module CallbackParams = +module CallbackParams = // https://www.ag-grid.com/react-data-grid/column-properties/#reference-editing-valueSetter // https://www.ag-grid.com/javascript-data-grid//column-properties/#reference-editing-valueParser [] @@ -140,7 +134,7 @@ module CallbackParams = type RowSelection = Single | Multiple [] -type RowGroupingDisplayType = +type RowGroupingDisplayType = | SingleColumn | MultipleColumns | GroupRows @@ -153,7 +147,7 @@ type RowGroupingDisplayType = | Custom -> "custom" [] -type RowGroupPanelShow = +type RowGroupPanelShow = | Always | OnlyWhenGrouping | Never member this.RowGroupPanelShowText = match this with @@ -162,14 +156,14 @@ type RowGroupPanelShow = | Never -> "never" [] -type RowFilter = +type RowFilter = | Number | Text | Date | Set member this.FilterText = sprintf "ag%OColumnFilter" this [] -type CellDataType = +type CellDataType = | Text | Number | Date | DateString | Boolean | Object | Custom of string - member this.CellDataTypeText = + member this.CellDataTypeText = match this with | Text -> "text" | Number -> "number" @@ -177,13 +171,13 @@ type CellDataType = | DateString -> "dateString" | Boolean -> "boolean" | Object -> "object" - | Custom s -> s + | Custom s -> s [] type AgCellEditor = | SelectCellEditor - | RichSelectCellEditor - | NumberCellEditor + | RichSelectCellEditor + | NumberCellEditor | DateCellEditor | DateStringCellEditor | CheckboxCellEditor @@ -194,7 +188,7 @@ type AgCellEditor = [] -type AggregateFunction = +type AggregateFunction = | Sum | Min | Max | Count | Avg | First | Last member this.AggregateText = (sprintf "%O" this).ToLower() @@ -245,11 +239,11 @@ type ColumnDef<'row, 'value> = [] static member cellRendererFramework _ = failwith "cellRendererFramework isn't supported in the latest version of AgGrid. Use cellRenderer instead" - + // Removed to resolve type inference issue with multiple overloads //static member cellRenderer' (render: 'value -> 'row -> ReactElement) = columnDefProp<'row, 'value> ("cellRenderer" ==> fun (p: ICellRendererParams<'row, 'value>) -> CellRendererComponentSimple(render, p.value, p.data)) static member cellRenderer (render: ICellRendererParams<'row, 'value> -> ReactElement) = columnDefProp<'row, 'value> ("cellRenderer" ==> fun p -> CellRendererComponent(render, p)) - + // Removed to resolve type inference issue with multiple overloads //static member cellEditor' (render: 'value -> 'row -> ReactElement) = columnDefProp<'row, 'value> ("cellEditor" ==> fun (p: ICellRendererParams<'row, 'value>) -> CellRendererComponentSimple(render, p.value, p.data)) static member cellEditor (render: ICellRendererParams<'row, 'value> -> ReactElement) = columnDefProp<'row, 'value> ("cellEditor" ==> fun p -> CellRendererComponent(render, p)) @@ -265,20 +259,20 @@ type ColumnDef<'row, 'value> = static member inline columnGroupShow (v:bool) = columnDefProp<'row, 'value> ("columnGroupShow" ==> openClosed v) static member inline columnType ct = columnDefProp<'row, 'value> ("type" ==> match ct with RightAligned -> "rightAligned" | NumericColumn -> "numericColumn") static member inline comparator (callback: 'a -> 'a -> int) = columnDefProp<'row, 'value> ("comparator" ==> fun a b -> callback a b) - + static member inline editable (callback:'value -> 'row -> bool) = columnDefProp<'row, 'value> ("editable" ==> fun p -> callback p?value p?data) static member inline editable (v: bool) = columnDefProp<'row, 'value> ("editable" ==> v) static member inline equals (callback: 'value -> 'value -> bool) = columnDefProp<'row, 'value> ("equals" ==> callback) static member inline enableRowGroup (v:bool) = columnDefProp<'row, 'value> ("enableRowGroup" ==> v) static member inline enableCellChangeFlash (v:bool) = columnDefProp<'row, 'value> ("enableCellChangeFlash" ==> v) //static member inline field (v:'a -> string) = columnDefProp<'row, 'value> ("field" ==> v (unbox null)) - static member inline field (v:string) = columnDefProp<'row, 'value> ("field" ==> v) - static member inline field (f: 'row -> _) = + static member inline field (v:string) = columnDefProp<'row, 'value> ("field" ==> v) + static member inline field (f: 'row -> _) = // usage: `AgGrid.field _.FirstName` or `AgGrid.field (fun x -> x.FirstName)` // Result = "FirstName" // Get everthing after first '.' let idxOfFirstDot = (string f).IndexOf('.') - let field = (string f).Substring(idxOfFirstDot + 1) + let field = (string f).Substring(idxOfFirstDot + 1) columnDefProp<'row, 'value> ("field" ==> field) static member inline filter (v:RowFilter) = columnDefProp<'row, 'value> ("filter" ==> v.FilterText) @@ -287,7 +281,7 @@ type ColumnDef<'row, 'value> = static member inline headerCheckboxSelection (v:bool) = columnDefProp<'row, 'value> ("headerCheckboxSelection" ==> v) static member inline headerClass (v:string) = columnDefProp<'row, 'value> ("headerClass" ==> v) static member inline headerComponentFramework (callback:'colId -> 'props -> ReactElement) = columnDefProp<'row, 'value> ("headerComponentFramework" ==> fun p -> callback p?column?colId p) - static member inline headerName (v:string) = columnDefProp<'row, 'value> ("headerName" ==> v) + static member inline headerName (v:string) = columnDefProp<'row, 'value> ("headerName" ==> v) static member inline wrapHeaderText (v:bool) = columnDefProp<'row, 'value> ("wrapHeaderText" ==> v) static member inline autoHeaderHeight (v:bool) = columnDefProp<'row, 'value> ("autoHeight" ==> v) static member inline hide (v:bool) = columnDefProp<'row, 'value> ("hide" ==> v) @@ -302,12 +296,12 @@ type ColumnDef<'row, 'value> = static member inline sortable (v:bool) = columnDefProp<'row, 'value> ("sortable" ==> v) static member inline suppressKeyboardEvent callback = columnDefProp<'row, 'value> ("suppressKeyboardEvent" ==> fun x -> callback x?event) static member inline suppressMovable = columnDefProp<'row, 'value> ("suppressMovable" ==> true) - + // Removed to resolve type inference issue with multiple overloads //static member inline valueFormatter (callback:'value -> 'row -> string) = columnDefProp<'row, 'value> ("valueFormatter" ==> (fun (p: IValueParams<'row, 'value>) -> callback p.value p.data)) static member inline valueFormatter (callback: IValueParams<'row, 'value> -> string) = columnDefProp<'row, 'value> ("valueFormatter" ==> callback) static member inline valueGetter (f:'row -> _) = columnDefProp<'row, 'value> ("valueGetter" ==> (fun x -> f x?data)) - static member inline valueSetter (f: IValueChangedParams<'row, 'value> -> unit) = columnDefProp<'row, 'value> ("valueSetter" ==> f) + static member inline valueSetter (f: IValueChangedParams<'row, 'value> -> unit) = columnDefProp<'row, 'value> ("valueSetter" ==> f) static member inline valueSetter (f: IValueChangedParams<'row, 'value> -> bool) = columnDefProp<'row, 'value> ("valueSetter" ==> f) static member inline valueParser (f: IValueChangedParams<'row, 'value> -> obj) = columnDefProp<'row, 'value> ("valueParser" ==> f) // Is never called by AgGrid static member inline width (v:int) = columnDefProp<'row, 'value> ("width" ==> v) @@ -370,7 +364,7 @@ type AgGrid<'row> = ev?columnApi?autoSizeColumns(colIds)) 0 |> ignore |} |> callback agGridProp<'row>("onColumnGroupOpened", onColumnGroupOpened) - + static member inline paginationPageSize (pageSize:int) = agGridProp<'row>("paginationPageSize", pageSize) static member inline paginationAutoPageSize (v:bool) = agGridProp<'row>("paginationAutoPageSize", v) static member inline pagination (v:bool) = agGridProp<'row>("pagination", v) From 4347315e12143a4c9640d7c33bf87a469142a35a Mon Sep 17 00:00:00 2001 From: Matt Gallagher Date: Fri, 24 May 2024 12:20:25 +0100 Subject: [PATCH 04/27] Run fantomas --- .config/dotnet-tools.json | 12 +- .editorconfig | 8 +- README.md | 21 +- demo/src/Components.fs | 324 ++++++++-------- demo/src/Extensions.fs | 12 +- demo/src/Main.fs | 6 +- src/AgGrid.fs | 760 ++++++++++++++++++++++++++------------ 7 files changed, 704 insertions(+), 439 deletions(-) diff --git a/.config/dotnet-tools.json b/.config/dotnet-tools.json index 8e01b65..a079483 100644 --- a/.config/dotnet-tools.json +++ b/.config/dotnet-tools.json @@ -14,17 +14,17 @@ "fable" ] }, - "fantomas-tool": { - "version": "4.4.0", - "commands": [ - "fantomas" - ] - }, "femto": { "version": "0.16.0", "commands": [ "femto" ] + }, + "fantomas": { + "version": "6.3.4", + "commands": [ + "fantomas" + ] } } } \ No newline at end of file diff --git a/.editorconfig b/.editorconfig index 2bd711f..5259d7a 100644 --- a/.editorconfig +++ b/.editorconfig @@ -5,8 +5,8 @@ indent_style = space indent_size = 4 charset = utf-8 trim_trailing_whitespace = true -insert_final_newline = false +insert_final_newline = true -[src/Client/*.fs] -# Feliz style -fsharp_single_argument_web_mode=true \ No newline at end of file +[*.{fs,fsx}] +fsharp_multiline_bracket_style = stroustrup +fsharp_newline_before_multiline_computation_expression = false diff --git a/README.md b/README.md index bbd87f3..5997a94 100644 --- a/README.md +++ b/README.md @@ -8,16 +8,18 @@ Feliz-style bindings for [ag-grid-react](https://www.npmjs.com/package/ag-grid-r Note: ag-grid-react/enterprise is only required if using enterprise features. -| Feliz.AgGrid | ag-grid-react/community | ag-grid-react/enterprise | React | Fable | Feliz | -|- |- | - |- |- |- | -| 2.x | 31.x | 31.x | 18.x | 4.x | 2.x | -| 1.x | 31.x | - | 18.x | 4.x | 2.x | -| 0.0.6 | 25.x | - | 17.x | 3.x | 1.x | +| Feliz.AgGrid | ag-grid-react/community | ag-grid-react/enterprise | React | Fable | Feliz | +|--------------|-------------------------|--------------------------|-------|-------|-------| +| 2.x | 31.x | 31.x | 18.x | 4.x | 2.x | +| 1.x | 31.x | - | 18.x | 4.x | 2.x | +| 0.0.6 | 25.x | - | 17.x | 3.x | 1.x | ### Migration guides #### v1 to v2 +##### Import AG Grid style sheets + To give you better control of your bundle, Feliz.AgGrid no longer imports styles for you, so you will need to include appropriate imports yourself. For example, add the following lines to your client code to import the necessary styles and the Balham theme. @@ -27,6 +29,12 @@ importAll "ag-grid-community/styles/ag-grid.css" importAll "ag-grid-community/styles/ag-theme-balham.css" ``` +##### AgGrid.onRangeSelectionChanged callback removed + +Fantomas was erroring when trying to format our previous implementation. We'll reinstate it once we have an +implementation that Fantomas can handle. Raise an issue if this is an important feature for you and we'll try to get +something working soon! + ## Installation Run `femto install Feliz.AgGrid` from inside your project directory. @@ -37,7 +45,8 @@ Found in `./src` ## Demo -Demo code is in `./demo`. You can see it running live at [https://compositionalit.github.io/feliz-ag-grid/](https://compositionalit.github.io/feliz-ag-grid/) +Demo code is in `./demo`. You can see it running live +at [https://compositionalit.github.io/feliz-ag-grid/](https://compositionalit.github.io/feliz-ag-grid/) ## Publishing a new package diff --git a/demo/src/Components.fs b/demo/src/Components.fs index 6441999..0c08cca 100644 --- a/demo/src/Components.fs +++ b/demo/src/Components.fs @@ -21,22 +21,20 @@ let container (children: ReactElement list) = style.flexDirection.column style.padding 50 style.maxWidth 1000 - style.margin (0,length.auto) + style.margin (0, length.auto) ] prop.children children ] let row (children: ReactElement list) = Html.div [ - prop.style [ - style.alignItems.center - style.display.flex - ] + prop.style [ style.alignItems.center; style.display.flex ] prop.children children ] let navbar () = - let logo : string = importDefault "./cit-logo.png" + let logo: string = importDefault "./cit-logo.png" + Html.div [ prop.style [ style.padding (0, 20) @@ -59,17 +57,9 @@ let navbar () = ] prop.children [ row [ - Html.img [ - prop.style [ - style.height 50 - ] - prop.src logo - ] + Html.img [ prop.style [ style.height 50 ]; prop.src logo ] Bulma.title [ - prop.style [ - style.color.white - style.fontSize (length.rem 1.5) - ] + prop.style [ style.color.white; style.fontSize (length.rem 1.5) ] prop.text "Compositional IT" ] ] @@ -81,7 +71,7 @@ let navbar () = let subHeading (label: string) = Bulma.subtitle [ prop.style [ - style.borderBottom(2, borderStyle.solid, citDarkBlue) + style.borderBottom (2, borderStyle.solid, citDarkBlue) style.marginTop 30 style.paddingBottom 10 ] @@ -106,18 +96,12 @@ let description (wrapperName: string) (wrappedComponent: string) links = Bulma.content [ Html.ul [ for l in links do - Html.li [ - link l - ] + Html.li [ link l ] ] ] ] -let headingWithContent (title: string) (children: ReactElement) = - Html.div [ - subHeading title - children - ] +let headingWithContent (title: string) (children: ReactElement) = Html.div [ subHeading title; children ] let codeBlock (code: string) = Html.pre [ @@ -130,174 +114,175 @@ let codeBlock (code: string) = prop.text code ] -type Olympian = - { Athlete: string - Age: int option - Country: string - Year: int - Date: string - Sport: string - Gold: int - Silver: int - Bronze: int - Total: int } +type Olympian = { + Athlete: string + Age: int option + Country: string + Year: int + Date: string + Sport: string + Gold: int + Silver: int + Bronze: int + Total: int +} [] let Demo () = - let (olympicData, setOlympicData) = React.useState(None) - let getData (): JS.Promise = - promise { - let url = sprintf "https://www.ag-grid.com/example-assets/olympic-winners.json" - return! Fetch.get(url, caseStrategy = CamelCase) - } + let (olympicData, setOlympicData) = React.useState (None) + + let getData () : JS.Promise = promise { + let url = sprintf "https://www.ag-grid.com/example-assets/olympic-winners.json" + return! Fetch.get (url, caseStrategy = CamelCase) + } React.useEffectOnce (fun () -> - let d = getData() - d.``then``(fun data -> - data - |> Some - |> setOlympicData) - |> ignore) + let d = getData () + d.``then`` (fun data -> data |> Some |> setOlympicData) |> ignore) let updateRowAthleteName newName row = olympicData |> Option.iter ( Array.map (fun x -> if x = row then { row with Athlete = newName } else x) >> Some - >> setOlympicData) + >> setOlympicData + ) container [ Html.div [ prop.style [ style.display.flex; style.flexWrap.wrap; style.flexDirection.column ] prop.children [ Html.div [ - description - "Feliz.AgGrid" - "ag-grid" - [ - { Text = "GitHub repo"; Href = "https://github.com/CompositionalIT/feliz-ag-grid" } - { Text = "NuGet package"; Href = "https://www.nuget.org/packages/Feliz.AgGrid" } - { Text = "Corresponding npm package"; Href = "https://www.npmjs.com/package/ag-grid-react" } - ] + description "Feliz.AgGrid" "ag-grid" [ + { + Text = "GitHub repo" + Href = "https://github.com/CompositionalIT/feliz-ag-grid" + } + { + Text = "NuGet package" + Href = "https://www.nuget.org/packages/Feliz.AgGrid" + } + { + Text = "Corresponding npm package" + Href = "https://www.npmjs.com/package/ag-grid-react" + } + ] headingWithContent "Demo" (match olympicData with - | Some olympicData -> - Html.div [ - prop.className ThemeClass.Balham - prop.children [ - AgGrid.grid [ - AgGrid.rowData olympicData - AgGrid.pagination true - AgGrid.defaultColDef [ - ColumnDef.resizable true - ColumnDef.sortable true - ] - AgGrid.domLayout AutoHeight - AgGrid.paginationPageSize 20 - AgGrid.onColumnGroupOpened (fun x -> x.AutoSizeGroupColumns()) - AgGrid.onGridReady (fun x -> x.AutoSizeAllColumns()) - AgGrid.singleClickEdit true - AgGrid.enableCellTextSelection true - AgGrid.ensureDomOrder true - AgGrid.columnDefs [ - ColumnDef.create [ - ColumnDef.filter RowFilter.Text - ColumnDef.headerName "Athlete (editable)" - ColumnDef.valueGetter (fun x -> x.Athlete) - ColumnDef.editable (fun _ _ -> true) - ColumnDef.valueSetter (fun newValue _ row -> updateRowAthleteName newValue row) - ] - ColumnDef.create [ - ColumnDef.filter RowFilter.Number - ColumnDef.columnType ColumnType.NumericColumn - ColumnDef.headerName "Age" - ColumnDef.valueGetter (fun x -> x.Age) - ColumnDef.valueFormatter (fun age _ -> - match age with - | Some age -> $"{age} years" - | None -> "Unknown" ) - ] - ColumnDef.create [ - ColumnDef.filter RowFilter.Text - ColumnDef.headerName "Country" - ColumnDef.valueGetter (fun x -> x.Country) - ] - ColumnDef.create [ - ColumnDef.filter RowFilter.Date - ColumnDef.headerName "Date" - ColumnDef.valueGetter (fun x -> - x.Date.Split("/") - |> function - | [| d; m; y |] -> DateTime(int y, int m, int d) - | _ -> DateTime.MinValue) - ColumnDef.valueFormatter (fun d _ -> d.ToShortDateString()) - ] - ColumnDef.create [ - ColumnDef.filter RowFilter.Text - ColumnDef.headerName "Sport" - ColumnDef.valueGetter (fun x -> x.Sport) - ] - ColumnGroup.create [ - ColumnGroup.headerName "Medal" - ColumnGroup.marryChildren true - ColumnGroup.openByDefault true - ] [ - ColumnDef.create [ - ColumnDef.filter RowFilter.Number - ColumnDef.headerName "Total" - ColumnDef.columnType ColumnType.NumericColumn - ColumnDef.valueGetter (fun x -> x.Total) - ColumnDef.cellRenderer (fun x _ -> - Html.span [ - Html.span [ - prop.style [ style.fontSize 9 ] - prop.children [ - Html.text "🏅" - ] - ] - Html.textf "%i" x - ]) - ColumnDef.columnGroupShow true - ] - ColumnDef.create [ - ColumnDef.filter RowFilter.Number - ColumnDef.headerName "Gold" - ColumnDef.columnType ColumnType.NumericColumn - ColumnDef.valueGetter (fun x -> x.Gold) - ColumnDef.columnGroupShow false - ] - ColumnDef.create [ - ColumnDef.filter RowFilter.Number - ColumnDef.headerName "Silver" - ColumnDef.columnType ColumnType.NumericColumn - ColumnDef.valueGetter (fun x -> x.Silver) - ColumnDef.columnGroupShow false - ] - ColumnDef.create [ - ColumnDef.filter RowFilter.Number - ColumnDef.headerName "Bronze" - ColumnDef.columnType ColumnType.NumericColumn - ColumnDef.valueGetter (fun x -> x.Bronze) - ColumnDef.columnGroupShow false - ] - ] - ] - ] - ] - ] - | None -> - Html.div []) + | Some olympicData -> + Html.div [ + prop.className ThemeClass.Balham + prop.children [ + AgGrid.grid [ + AgGrid.rowData olympicData + AgGrid.pagination true + AgGrid.defaultColDef [ ColumnDef.resizable true; ColumnDef.sortable true ] + AgGrid.domLayout AutoHeight + AgGrid.paginationPageSize 20 + AgGrid.onColumnGroupOpened (fun x -> x.AutoSizeGroupColumns()) + AgGrid.onGridReady (fun x -> x.AutoSizeAllColumns()) + AgGrid.singleClickEdit true + AgGrid.enableCellTextSelection true + AgGrid.ensureDomOrder true + AgGrid.columnDefs [ + ColumnDef.create [ + ColumnDef.filter RowFilter.Text + ColumnDef.headerName "Athlete (editable)" + ColumnDef.valueGetter (fun x -> x.Athlete) + ColumnDef.editable (fun _ _ -> true) + ColumnDef.valueSetter (fun newValue _ row -> + updateRowAthleteName newValue row) + ] + ColumnDef.create [ + ColumnDef.filter RowFilter.Number + ColumnDef.columnType ColumnType.NumericColumn + ColumnDef.headerName "Age" + ColumnDef.valueGetter (fun x -> x.Age) + ColumnDef.valueFormatter (fun age _ -> + match age with + | Some age -> $"{age} years" + | None -> "Unknown") + ] + ColumnDef.create [ + ColumnDef.filter RowFilter.Text + ColumnDef.headerName "Country" + ColumnDef.valueGetter (fun x -> x.Country) + ] + ColumnDef.create [ + ColumnDef.filter RowFilter.Date + ColumnDef.headerName "Date" + ColumnDef.valueGetter (fun x -> + x.Date.Split("/") + |> function + | [| d; m; y |] -> DateTime(int y, int m, int d) + | _ -> DateTime.MinValue) + ColumnDef.valueFormatter (fun d _ -> d.ToShortDateString()) + ] + ColumnDef.create [ + ColumnDef.filter RowFilter.Text + ColumnDef.headerName "Sport" + ColumnDef.valueGetter (fun x -> x.Sport) + ] + ColumnGroup.create [ + ColumnGroup.headerName "Medal" + ColumnGroup.marryChildren true + ColumnGroup.openByDefault true + ] [ + ColumnDef.create [ + ColumnDef.filter RowFilter.Number + ColumnDef.headerName "Total" + ColumnDef.columnType ColumnType.NumericColumn + ColumnDef.valueGetter (fun x -> x.Total) + ColumnDef.cellRenderer (fun x _ -> + Html.span [ + Html.span [ + prop.style [ style.fontSize 9 ] + prop.children [ Html.text "🏅" ] + ] + Html.textf "%i" x + ]) + ColumnDef.columnGroupShow true + ] + ColumnDef.create [ + ColumnDef.filter RowFilter.Number + ColumnDef.headerName "Gold" + ColumnDef.columnType ColumnType.NumericColumn + ColumnDef.valueGetter (fun x -> x.Gold) + ColumnDef.columnGroupShow false + ] + ColumnDef.create [ + ColumnDef.filter RowFilter.Number + ColumnDef.headerName "Silver" + ColumnDef.columnType ColumnType.NumericColumn + ColumnDef.valueGetter (fun x -> x.Silver) + ColumnDef.columnGroupShow false + ] + ColumnDef.create [ + ColumnDef.filter RowFilter.Number + ColumnDef.headerName "Bronze" + ColumnDef.columnType ColumnType.NumericColumn + ColumnDef.valueGetter (fun x -> x.Bronze) + ColumnDef.columnGroupShow false + ] + ] + ] + ] + ] + ] + | None -> Html.div []) headingWithContent "Installation" - (codeBlock """ + (codeBlock + """ cd ./project -femto install Feliz.AgGrid""" ) +femto install Feliz.AgGrid""") headingWithContent "Sample Code" - (codeBlock """ + (codeBlock + """ open Feliz.AgGrid type Olympian = @@ -422,9 +407,4 @@ Html.div [ ] [] -let Documentation () = - Html.div [ - navbar() - Demo() - ] - +let Documentation () = Html.div [ navbar (); Demo() ] diff --git a/demo/src/Extensions.fs b/demo/src/Extensions.fs index f411780..f7ae0da 100644 --- a/demo/src/Extensions.fs +++ b/demo/src/Extensions.fs @@ -21,9 +21,11 @@ module Config = /// Tries to find the value of the configured variable if it is defined or returns a given default value otherwise. let variableOrDefault (key: string) (defaultValue: string) = let foundValue = variable key - if String.IsNullOrWhiteSpace foundValue - then defaultValue - else foundValue + + if String.IsNullOrWhiteSpace foundValue then + defaultValue + else + foundValue // Stylesheet API // let private stylehsheet = Stylesheet.load "./fancy.css" @@ -32,7 +34,7 @@ module Stylesheet = type IStylesheet = [] - abstract Item : className:string -> string + abstract Item: className: string -> string /// Loads a CSS module and makes the classes within available - let inline load (path: string) = importDefault path \ No newline at end of file + let inline load (path: string) = importDefault path diff --git a/demo/src/Main.fs b/demo/src/Main.fs index 2d17f0d..e969323 100644 --- a/demo/src/Main.fs +++ b/demo/src/Main.fs @@ -6,8 +6,6 @@ open Fable.Core.JsInterop importSideEffects "./styles/global.scss" -let root = ReactDOM.createRoot(document.getElementById "feliz-app") +let root = ReactDOM.createRoot (document.getElementById "feliz-app") -root.render( - App.Documentation() -) \ No newline at end of file +root.render (App.Documentation()) diff --git a/src/AgGrid.fs b/src/AgGrid.fs index 42753e4..e0824f2 100644 --- a/src/AgGrid.fs +++ b/src/AgGrid.fs @@ -1,58 +1,57 @@ -// fsharplint:disable module Feliz.AgGrid open System + open Fable.Core open Fable.Core.JsInterop open Feliz -let agGrid : obj = import "AgGridReact" "ag-grid-react" +let agGrid: obj = import "AgGridReact" "ag-grid-react" // https://www.ag-grid.com/javascript-data-grid/row-object/ [] type IRowNode<'row> = { id: string - data : 'row + data: 'row updateData: 'row -> unit setData: 'row -> unit - setSelected : bool -> unit - rowIndex : int - rowTop : int - displayed : bool - isHovered : bool - isFullWidthCell : bool - isSelected : bool + setSelected: bool -> unit + rowIndex: int + rowTop: int + displayed: bool + isHovered: bool + isFullWidthCell: bool + isSelected: bool } [] type ICellRange = { - id : string - startRow : obj - endRow : obj -} - with - member this.startRowIndex : int = this.startRow?rowIndex - member this.endRowIndex : int = this.endRow?rowIndex + id: string + startRow: obj + endRow: obj +} with + + member this.startRowIndex: int = this.startRow?rowIndex + member this.endRowIndex: int = this.endRow?rowIndex // https://www.ag-grid.com/javascript-data-grid/grid-interface/#grid-api [] type IGridApi<'row> = - abstract copyToClipboard : unit -> unit - abstract pasteFromClipboard : unit -> unit - abstract refreshCells : unit -> unit - abstract redrawRows : unit -> unit - abstract setGridOption : string -> obj -> unit - abstract getSelectedNodes : unit -> IRowNode<'row>[] - abstract getCellRanges : unit -> ICellRange[] + abstract copyToClipboard: unit -> unit + abstract pasteFromClipboard: unit -> unit + abstract refreshCells: unit -> unit + abstract redrawRows: unit -> unit + abstract setGridOption: string -> obj -> unit + abstract getSelectedNodes: unit -> IRowNode<'row>[] + abstract getCellRanges: unit -> ICellRange[] // https://www.ag-grid.com/javascript-data-grid/column-object/ [] -type IColumn = { - getColId : unit -> string -} +type IColumn = { getColId: unit -> string } [] type IColumnDefProp<'row, 'value> = interface end + let columnDefProp<'row, 'value> = unbox> [] @@ -64,74 +63,77 @@ module CallbackParams = // https://www.ag-grid.com/javascript-data-grid//column-properties/#reference-editing-valueParser [] type IValueChangedParams<'row, 'value> = { - oldValue : 'value - newValue : 'value - node : IRowNode<'row> - data : 'row - column : IColumn + oldValue: 'value + newValue: 'value + node: IRowNode<'row> + data: 'row + column: IColumn colDef: IColumnDef<'row> - api : IGridApi<'row> - } - with member this.rowIndex = this.node.rowIndex + api: IGridApi<'row> + } with + + member this.rowIndex = this.node.rowIndex // https://www.ag-grid.com/javascript-data-grid/component-cell-editor/#reference-ICellEditorParams [] type IValueParams<'row, 'value> = { - value : 'value - data : 'row - node : IRowNode<'row> - colDef : IColumnDef<'row> - column : IColumn - api : IGridApi<'row> + value: 'value + data: 'row + node: IRowNode<'row> + colDef: IColumnDef<'row> + column: IColumn + api: IGridApi<'row> rowIndex: int } // https://www.ag-grid.com/javascript-data-grid/grid-events/#reference-selection-cellFocused [] type ICellFocusedEvent<'row> = { - api : IGridApi<'row> - rowIndex : int - column : IColumn + api: IGridApi<'row> + rowIndex: int + column: IColumn isFullWidthCell: bool } // https://www.ag-grid.com/javascript-data-grid//grid-options/#reference-rowModels-getRowId [] type IGetRowIdParams<'row> = { - data : 'row - level : int + data: 'row + level: int parentKeys: string[] - api : IGridApi<'row> + api: IGridApi<'row> context: obj } [] type ICellRendererParams<'row, 'value> = { - value : 'value - data : 'row - node : IRowNode<'row> - colDef : IColumnDef<'row> - column : IColumn - api : IGridApi<'row> + value: 'value + data: 'row + node: IRowNode<'row> + colDef: IColumnDef<'row> + column: IColumn + api: IGridApi<'row> rowIndex: int } [] type IPasteEvent<'row> = { - source : string - api : IGridApi<'row> - context : obj - ``type`` : string + source: string + api: IGridApi<'row> + context: obj + ``type``: string } [] type IProcessDataFromClipboardParams<'row> = { - data : string[][] - api : IGridApi<'row> - context : obj + data: string[][] + api: IGridApi<'row> + context: obj } -type RowSelection = Single | Multiple +type RowSelection = + | Single + | Multiple [] type RowGroupingDisplayType = @@ -139,6 +141,7 @@ type RowGroupingDisplayType = | MultipleColumns | GroupRows | Custom + member this.RowGroupingDisplayTypeText = match this with | SingleColumn -> "singleColumn" @@ -148,7 +151,10 @@ type RowGroupingDisplayType = [] type RowGroupPanelShow = - | Always | OnlyWhenGrouping | Never + | Always + | OnlyWhenGrouping + | Never + member this.RowGroupPanelShowText = match this with | Always -> "always" @@ -157,12 +163,23 @@ type RowGroupPanelShow = [] type RowFilter = - | Number | Text | Date | Set + | Number + | Text + | Date + | Set + member this.FilterText = sprintf "ag%OColumnFilter" this [] type CellDataType = - | Text | Number | Date | DateString | Boolean | Object | Custom of string + | Text + | Number + | Date + | DateString + | Boolean + | Object + | Custom of string + member this.CellDataTypeText = match this with | Text -> "text" @@ -183,17 +200,27 @@ type AgCellEditor = | CheckboxCellEditor | LargeTextCellEditor | TextCellEditor - member this.RichCellEditorText = - sprintf "ag%O" this + + member this.RichCellEditorText = sprintf "ag%O" this [] type AggregateFunction = - | Sum | Min | Max | Count | Avg | First | Last + | Sum + | Min + | Max + | Count + | Avg + | First + | Last + member this.AggregateText = (sprintf "%O" this).ToLower() type DOMLayout = - Normal | AutoHeight | Print + | Normal + | AutoHeight + | Print + member this.LayoutText = match this with | Normal -> "normal" @@ -208,66 +235,128 @@ module ThemeClass = let Material = "ag-theme-material" type MenuItemDef = { - name : string - action : unit -> unit - shortcut : string - icon : obj //HtmlElement + name: string + action: unit -> unit + shortcut: string + icon: obj //HtmlElement } + type MenuItem = | BuiltIn of string | Custom of MenuItemDef -type ColumnType = RightAligned | NumericColumn +type ColumnType = + | RightAligned + | NumericColumn -let openClosed = function | true -> "open" | false -> "closed" +let openClosed = + function + | true -> "open" + | false -> "closed" [] -let CellRendererComponent<'row, 'value> (render: (ICellRendererParams<'row, 'value>) -> ReactElement, p: ICellRendererParams<'row, 'value>) = +let CellRendererComponent<'row, 'value> + (render: ICellRendererParams<'row, 'value> -> ReactElement, p: ICellRendererParams<'row, 'value>) + = render p [] type ColumnDef<'row, 'value> = - static member inline create (props: IColumnDefProp<'row, 'value> seq) = createObj !!props :?> IColumnDef<'row> + static member inline create(props: IColumnDefProp<'row, 'value> seq) = createObj !!props :?> IColumnDef<'row> + + static member inline aggFunc(v: AggregateFunction) = + columnDefProp<'row, 'value> ("aggFunc" ==> v.AggregateText) - static member inline aggFunc (v:AggregateFunction) = columnDefProp<'row, 'value> ("aggFunc" ==> v.AggregateText) static member inline autoComparator = columnDefProp<'row, 'value> ("comparator" ==> compare) - static member inline cellClass (setClass:'value -> 'row -> #seq) = columnDefProp<'row, 'value> ("cellClass" ==> fun p -> setClass p?value p?data |> Seq.toArray) - static member inline cellClassRules (rules: (string*('value -> 'row -> bool)) list) = columnDefProp<'row, 'value> ("cellClassRules" ==> (rules |> List.map (fun (className, rule) -> className ==> fun p -> rule p?value p?data) |> createObj)) - static member cellDataType (v:bool) = columnDefProp<'row, 'value> ("cellDataType" ==> v) - static member cellDataType (v:CellDataType) = columnDefProp<'row, 'value> ("cellDataType" ==> v.CellDataTypeText) + static member inline cellClass(setClass: 'value -> 'row -> #seq) = + columnDefProp<'row, 'value> ("cellClass" ==> fun p -> setClass p?value p?data |> Seq.toArray) + + static member inline cellClassRules(rules: (string * ('value -> 'row -> bool)) list) = + columnDefProp<'row, 'value> ( + "cellClassRules" + ==> (rules + |> List.map (fun (className, rule) -> className ==> fun p -> rule p?value p?data) + |> createObj) + ) + + static member cellDataType(v: bool) = + columnDefProp<'row, 'value> ("cellDataType" ==> v) + + static member cellDataType(v: CellDataType) = + columnDefProp<'row, 'value> ("cellDataType" ==> v.CellDataTypeText) [] - static member cellRendererFramework _ = failwith "cellRendererFramework isn't supported in the latest version of AgGrid. Use cellRenderer instead" + static member cellRendererFramework _ = + failwith "cellRendererFramework isn't supported in the latest version of AgGrid. Use cellRenderer instead" // Removed to resolve type inference issue with multiple overloads //static member cellRenderer' (render: 'value -> 'row -> ReactElement) = columnDefProp<'row, 'value> ("cellRenderer" ==> fun (p: ICellRendererParams<'row, 'value>) -> CellRendererComponentSimple(render, p.value, p.data)) - static member cellRenderer (render: ICellRendererParams<'row, 'value> -> ReactElement) = columnDefProp<'row, 'value> ("cellRenderer" ==> fun p -> CellRendererComponent(render, p)) + static member cellRenderer(render: ICellRendererParams<'row, 'value> -> ReactElement) = + columnDefProp<'row, 'value> ("cellRenderer" ==> fun p -> CellRendererComponent(render, p)) // Removed to resolve type inference issue with multiple overloads //static member cellEditor' (render: 'value -> 'row -> ReactElement) = columnDefProp<'row, 'value> ("cellEditor" ==> fun (p: ICellRendererParams<'row, 'value>) -> CellRendererComponentSimple(render, p.value, p.data)) - static member cellEditor (render: ICellRendererParams<'row, 'value> -> ReactElement) = columnDefProp<'row, 'value> ("cellEditor" ==> fun p -> CellRendererComponent(render, p)) - static member cellEditor (v:string) = columnDefProp<'row, 'value> ("cellEditor" ==> v) - static member cellEditor (v: AgCellEditor) = columnDefProp<'row, 'value> ("cellEditor" ==> v.RichCellEditorText) - - static member cellEditorParams (v: string seq) = columnDefProp<'row, 'value> ("cellEditorParams" ==> {| values = v |> Seq.toArray |}) - static member cellEditorParams (v: obj) = columnDefProp<'row, 'value> ("cellEditorParams" ==> v) - static member cellEditorPopup (v:bool) = columnDefProp<'row, 'value> ("cellEditorPopup" ==> v) - static member inline cellStyle (setStyle:'value -> 'row -> _) = columnDefProp<'row, 'value> ("cellStyle" ==> fun p -> setStyle p?value p?data) - static member inline checkboxSelection (v:bool) = columnDefProp<'row, 'value> ("checkboxSelection" ==> v) - static member inline colId (v:string) = columnDefProp<'row, 'value> ("colId" ==> v) - static member inline columnGroupShow (v:bool) = columnDefProp<'row, 'value> ("columnGroupShow" ==> openClosed v) - static member inline columnType ct = columnDefProp<'row, 'value> ("type" ==> match ct with RightAligned -> "rightAligned" | NumericColumn -> "numericColumn") - static member inline comparator (callback: 'a -> 'a -> int) = columnDefProp<'row, 'value> ("comparator" ==> fun a b -> callback a b) - - static member inline editable (callback:'value -> 'row -> bool) = columnDefProp<'row, 'value> ("editable" ==> fun p -> callback p?value p?data) - static member inline editable (v: bool) = columnDefProp<'row, 'value> ("editable" ==> v) - static member inline equals (callback: 'value -> 'value -> bool) = columnDefProp<'row, 'value> ("equals" ==> callback) - static member inline enableRowGroup (v:bool) = columnDefProp<'row, 'value> ("enableRowGroup" ==> v) - static member inline enableCellChangeFlash (v:bool) = columnDefProp<'row, 'value> ("enableCellChangeFlash" ==> v) + static member cellEditor(render: ICellRendererParams<'row, 'value> -> ReactElement) = + columnDefProp<'row, 'value> ("cellEditor" ==> fun p -> CellRendererComponent(render, p)) + + static member cellEditor(v: string) = + columnDefProp<'row, 'value> ("cellEditor" ==> v) + + static member cellEditor(v: AgCellEditor) = + columnDefProp<'row, 'value> ("cellEditor" ==> v.RichCellEditorText) + + static member cellEditorParams(v: string seq) = + columnDefProp<'row, 'value> ("cellEditorParams" ==> {| values = v |> Seq.toArray |}) + + static member cellEditorParams(v: obj) = + columnDefProp<'row, 'value> ("cellEditorParams" ==> v) + + static member cellEditorPopup(v: bool) = + columnDefProp<'row, 'value> ("cellEditorPopup" ==> v) + + static member inline cellStyle(setStyle: 'value -> 'row -> _) = + columnDefProp<'row, 'value> ("cellStyle" ==> fun p -> setStyle p?value p?data) + + static member inline checkboxSelection(v: bool) = + columnDefProp<'row, 'value> ("checkboxSelection" ==> v) + + static member inline colId(v: string) = + columnDefProp<'row, 'value> ("colId" ==> v) + + static member inline columnGroupShow(v: bool) = + columnDefProp<'row, 'value> ("columnGroupShow" ==> openClosed v) + + static member inline columnType ct = + columnDefProp<'row, 'value> ( + "type" + ==> match ct with + | RightAligned -> "rightAligned" + | NumericColumn -> "numericColumn" + ) + + static member inline comparator(callback: 'a -> 'a -> int) = + columnDefProp<'row, 'value> ("comparator" ==> fun a b -> callback a b) + + static member inline editable(callback: 'value -> 'row -> bool) = + columnDefProp<'row, 'value> ("editable" ==> fun p -> callback p?value p?data) + + static member inline editable(v: bool) = + columnDefProp<'row, 'value> ("editable" ==> v) + + static member inline equals(callback: 'value -> 'value -> bool) = + columnDefProp<'row, 'value> ("equals" ==> callback) + + static member inline enableRowGroup(v: bool) = + columnDefProp<'row, 'value> ("enableRowGroup" ==> v) + + static member inline enableCellChangeFlash(v: bool) = + columnDefProp<'row, 'value> ("enableCellChangeFlash" ==> v) //static member inline field (v:'a -> string) = columnDefProp<'row, 'value> ("field" ==> v (unbox null)) - static member inline field (v:string) = columnDefProp<'row, 'value> ("field" ==> v) - static member inline field (f: 'row -> _) = + static member inline field(v: string) = + columnDefProp<'row, 'value> ("field" ==> v) + + static member inline field(f: 'row -> _) = // usage: `AgGrid.field _.FirstName` or `AgGrid.field (fun x -> x.FirstName)` // Result = "FirstName" // Get everthing after first '.' @@ -275,160 +364,347 @@ type ColumnDef<'row, 'value> = let field = (string f).Substring(idxOfFirstDot + 1) columnDefProp<'row, 'value> ("field" ==> field) - static member inline filter (v:RowFilter) = columnDefProp<'row, 'value> ("filter" ==> v.FilterText) - static member inline filter (v:bool) = columnDefProp<'row, 'value> ("filter" ==> v) - static member inline floatingFilter (v:bool) = columnDefProp<'row, 'value> ("floatingFilter" ==> v) - static member inline headerCheckboxSelection (v:bool) = columnDefProp<'row, 'value> ("headerCheckboxSelection" ==> v) - static member inline headerClass (v:string) = columnDefProp<'row, 'value> ("headerClass" ==> v) - static member inline headerComponentFramework (callback:'colId -> 'props -> ReactElement) = columnDefProp<'row, 'value> ("headerComponentFramework" ==> fun p -> callback p?column?colId p) - static member inline headerName (v:string) = columnDefProp<'row, 'value> ("headerName" ==> v) - static member inline wrapHeaderText (v:bool) = columnDefProp<'row, 'value> ("wrapHeaderText" ==> v) - static member inline autoHeaderHeight (v:bool) = columnDefProp<'row, 'value> ("autoHeight" ==> v) - static member inline hide (v:bool) = columnDefProp<'row, 'value> ("hide" ==> v) - static member inline maxWidth (v:int) = columnDefProp<'row, 'value> ("maxWidth" ==> v) - static member inline minWidth (v:int) = columnDefProp<'row, 'value> ("minWidth" ==> v) - static member inline onCellClicked (handler:'value -> 'row -> unit) = columnDefProp<'row, 'value> ("onCellClicked" ==> (fun p -> handler p?value p?data)) - static member inline pinned (v:bool) = columnDefProp<'row, 'value> ("pinned" ==> v) - static member inline pivot(v:bool) = columnDefProp<'row, 'value> ("pivot" ==> v) - static member inline resizable (v:bool) = columnDefProp<'row, 'value> ("resizable" ==> v) - static member inline rowDrag (v:bool) = columnDefProp<'row, 'value> ("rowDrag" ==> v) - static member inline rowGroup (v:bool) = columnDefProp<'row, 'value> ("rowGroup" ==> v) - static member inline sortable (v:bool) = columnDefProp<'row, 'value> ("sortable" ==> v) - static member inline suppressKeyboardEvent callback = columnDefProp<'row, 'value> ("suppressKeyboardEvent" ==> fun x -> callback x?event) - static member inline suppressMovable = columnDefProp<'row, 'value> ("suppressMovable" ==> true) + static member inline filter(v: RowFilter) = + columnDefProp<'row, 'value> ("filter" ==> v.FilterText) + + static member inline filter(v: bool) = + columnDefProp<'row, 'value> ("filter" ==> v) + + static member inline floatingFilter(v: bool) = + columnDefProp<'row, 'value> ("floatingFilter" ==> v) + + static member inline headerCheckboxSelection(v: bool) = + columnDefProp<'row, 'value> ("headerCheckboxSelection" ==> v) + + static member inline headerClass(v: string) = + columnDefProp<'row, 'value> ("headerClass" ==> v) + + static member inline headerComponentFramework(callback: 'colId -> 'props -> ReactElement) = + columnDefProp<'row, 'value> ("headerComponentFramework" ==> fun p -> callback p?column?colId p) + + static member inline headerName(v: string) = + columnDefProp<'row, 'value> ("headerName" ==> v) + + static member inline wrapHeaderText(v: bool) = + columnDefProp<'row, 'value> ("wrapHeaderText" ==> v) + + static member inline autoHeaderHeight(v: bool) = + columnDefProp<'row, 'value> ("autoHeight" ==> v) + + static member inline hide(v: bool) = + columnDefProp<'row, 'value> ("hide" ==> v) + + static member inline maxWidth(v: int) = + columnDefProp<'row, 'value> ("maxWidth" ==> v) + + static member inline minWidth(v: int) = + columnDefProp<'row, 'value> ("minWidth" ==> v) + + static member inline onCellClicked(handler: 'value -> 'row -> unit) = + columnDefProp<'row, 'value> ("onCellClicked" ==> (fun p -> handler p?value p?data)) + + static member inline pinned(v: bool) = + columnDefProp<'row, 'value> ("pinned" ==> v) + + static member inline pivot(v: bool) = + columnDefProp<'row, 'value> ("pivot" ==> v) + + static member inline resizable(v: bool) = + columnDefProp<'row, 'value> ("resizable" ==> v) + + static member inline rowDrag(v: bool) = + columnDefProp<'row, 'value> ("rowDrag" ==> v) + + static member inline rowGroup(v: bool) = + columnDefProp<'row, 'value> ("rowGroup" ==> v) + + static member inline sortable(v: bool) = + columnDefProp<'row, 'value> ("sortable" ==> v) + + static member inline suppressKeyboardEvent callback = + columnDefProp<'row, 'value> ("suppressKeyboardEvent" ==> fun x -> callback x?event) + + static member inline suppressMovable = + columnDefProp<'row, 'value> ("suppressMovable" ==> true) // Removed to resolve type inference issue with multiple overloads //static member inline valueFormatter (callback:'value -> 'row -> string) = columnDefProp<'row, 'value> ("valueFormatter" ==> (fun (p: IValueParams<'row, 'value>) -> callback p.value p.data)) - static member inline valueFormatter (callback: IValueParams<'row, 'value> -> string) = columnDefProp<'row, 'value> ("valueFormatter" ==> callback) - static member inline valueGetter (f:'row -> _) = columnDefProp<'row, 'value> ("valueGetter" ==> (fun x -> f x?data)) - static member inline valueSetter (f: IValueChangedParams<'row, 'value> -> unit) = columnDefProp<'row, 'value> ("valueSetter" ==> f) - static member inline valueSetter (f: IValueChangedParams<'row, 'value> -> bool) = columnDefProp<'row, 'value> ("valueSetter" ==> f) - static member inline valueParser (f: IValueChangedParams<'row, 'value> -> obj) = columnDefProp<'row, 'value> ("valueParser" ==> f) // Is never called by AgGrid - static member inline width (v:int) = columnDefProp<'row, 'value> ("width" ==> v) + static member inline valueFormatter(callback: IValueParams<'row, 'value> -> string) = + columnDefProp<'row, 'value> ("valueFormatter" ==> callback) + + static member inline valueGetter(f: 'row -> _) = + columnDefProp<'row, 'value> ("valueGetter" ==> (fun x -> f x?data)) + + static member inline valueSetter(f: IValueChangedParams<'row, 'value> -> unit) = + columnDefProp<'row, 'value> ("valueSetter" ==> f) + + static member inline valueSetter(f: IValueChangedParams<'row, 'value> -> bool) = + columnDefProp<'row, 'value> ("valueSetter" ==> f) + + static member inline valueParser(f: IValueChangedParams<'row, 'value> -> obj) = + columnDefProp<'row, 'value> ("valueParser" ==> f) // Is never called by AgGrid + + static member inline width(v: int) = + columnDefProp<'row, 'value> ("width" ==> v) [] type IColumnGroupDefProp<'row> = interface end + let columnGroupDefProp<'row> = unbox> [] type ColumnGroup<'row> = - static member inline headerName (v:string) = columnGroupDefProp<'row> ("headerName" ==> v) - static member inline marryChildren(v:bool) = columnGroupDefProp<'row> ("marryChildren" ==> v) - static member inline openByDefault(v:bool) = columnGroupDefProp<'row> ("openByDefault" ==> v) + static member inline headerName(v: string) = + columnGroupDefProp<'row> ("headerName" ==> v) + + static member inline marryChildren(v: bool) = + columnGroupDefProp<'row> ("marryChildren" ==> v) + + static member inline openByDefault(v: bool) = + columnGroupDefProp<'row> ("openByDefault" ==> v) - static member inline create (props:seq>) (children:seq>) = - props |> Seq.append [(columnGroupDefProp<'row> ("children" ==> Seq.toArray children))] |> unbox<_ seq> |> createObj |> unbox> + static member inline create (props: seq>) (children: seq>) = + props + |> Seq.append [ (columnGroupDefProp<'row> ("children" ==> Seq.toArray children)) ] + |> unbox<_ seq> + |> createObj + |> unbox> [] type IAgGridProp<'row> = interface end -let agGridProp<'row> (x:obj) = unbox> x + +let agGridProp<'row> (x: obj) = unbox> x [] type AgGrid<'row> = - static member inline animateRows (v:bool) = agGridProp<'row>("animateRows" ==> v) - static member inline alwaysShowVerticalScroll (v:bool) = agGridProp<'row>("alwaysShowVerticalScroll" ==> v) - static member inline columnDefs (columns:IColumnDef<'row> seq) = agGridProp<'row>("columnDefs", columns |> unbox |> Seq.toArray) - static member inline copyHeadersToClipboard (v:bool) = agGridProp<'row>("copyHeadersToClipboard" ==> v) - static member inline domLayout (l:DOMLayout) = agGridProp<'row>("domLayout", l.LayoutText) - static member inline enableCellTextSelection (v:bool) = agGridProp<'row> ("enableCellTextSelection" ==> v) - static member inline ensureDomOrder (v:bool) = agGridProp<'row> ("ensureDomOrder" ==> v) - static member inline enterNavigatesVertically (v:bool) = agGridProp<'row> ("enterNavigatesVertically" ==> v) - static member inline getRowNodeId (callback: 'row -> _) = agGridProp<'row>("getRowNodeId", callback) - static member inline getRowId (callback: IGetRowIdParams<'row> -> string) = agGridProp<'row>("getRowId", callback) - static member inline onCellEditRequest (callback: obj -> unit) = agGridProp<'row>("onCellEditRequest", callback) - static member inline onCellValueChanged callback = agGridProp<'row>("onCellValueChanged", fun x -> callback x?data) - static member inline onPasteStart (callback: IPasteEvent<'row> -> unit) = agGridProp<'row>("onPasteStart", callback) - static member inline onPasteEnd (callback: IPasteEvent<'row> -> unit) = agGridProp<'row>("onPasteEnd", callback) - static member inline onRowClicked (handler:'value -> 'row -> unit) = agGridProp<'row> ("onRowClicked" ==> (fun p -> handler p?value p?data)) - static member inline onSelectionChanged (callback:'row array -> unit) = agGridProp<'row>("onSelectionChanged", fun x -> x?api?getSelectedRows() |> callback) - static member inline readOnlyEdit (v:bool) = agGridProp<'row>("readOnlyEdit" ==> v) - static member inline singleClickEdit (v:bool) = agGridProp<'row>("singleClickEdit" ==> v) - static member inline rowDeselection (v:bool) = agGridProp<'row>("rowDeselection", v) - static member inline rowSelection (s:RowSelection) = agGridProp<'row>("rowSelection", s.ToString().ToLower()) - static member inline isRowSelectable (callback:'row -> bool) = agGridProp<'row>("isRowSelectable" ==> fun x -> x?data |> callback) - static member inline suppressRowClickSelection (v:bool) = agGridProp<'row>("suppressRowClickSelection" ==> v) - static member inline rowHeight (h:int) = agGridProp<'row>("rowHeight", h) - static member inline immutableData (v:bool) = agGridProp<'row>("immutableData", v) + static member inline animateRows(v: bool) = agGridProp<'row> ("animateRows" ==> v) + + static member inline alwaysShowVerticalScroll(v: bool) = + agGridProp<'row> ("alwaysShowVerticalScroll" ==> v) + + static member inline columnDefs(columns: IColumnDef<'row> seq) = + agGridProp<'row> ("columnDefs", columns |> unbox |> Seq.toArray) + + static member inline copyHeadersToClipboard(v: bool) = + agGridProp<'row> ("copyHeadersToClipboard" ==> v) + + static member inline domLayout(l: DOMLayout) = + agGridProp<'row> ("domLayout", l.LayoutText) + + static member inline enableCellTextSelection(v: bool) = + agGridProp<'row> ("enableCellTextSelection" ==> v) + + static member inline ensureDomOrder(v: bool) = + agGridProp<'row> ("ensureDomOrder" ==> v) + + static member inline enterNavigatesVertically(v: bool) = + agGridProp<'row> ("enterNavigatesVertically" ==> v) + + static member inline getRowNodeId(callback: 'row -> _) = + agGridProp<'row> ("getRowNodeId", callback) + + static member inline getRowId(callback: IGetRowIdParams<'row> -> string) = agGridProp<'row> ("getRowId", callback) + + static member inline onCellEditRequest(callback: obj -> unit) = + agGridProp<'row> ("onCellEditRequest", callback) + + static member inline onCellValueChanged callback = + agGridProp<'row> ("onCellValueChanged", (fun x -> callback x?data)) + + static member inline onPasteStart(callback: IPasteEvent<'row> -> unit) = + agGridProp<'row> ("onPasteStart", callback) + + static member inline onPasteEnd(callback: IPasteEvent<'row> -> unit) = + agGridProp<'row> ("onPasteEnd", callback) + + static member inline onRowClicked(handler: 'value -> 'row -> unit) = + agGridProp<'row> ("onRowClicked" ==> (fun p -> handler p?value p?data)) + + static member inline onSelectionChanged(callback: 'row array -> unit) = + agGridProp<'row> ("onSelectionChanged", (fun x -> x?api?getSelectedRows () |> callback)) + + static member inline readOnlyEdit(v: bool) = agGridProp<'row> ("readOnlyEdit" ==> v) + + static member inline singleClickEdit(v: bool) = + agGridProp<'row> ("singleClickEdit" ==> v) + + static member inline rowDeselection(v: bool) = agGridProp<'row> ("rowDeselection", v) + + static member inline rowSelection(s: RowSelection) = + agGridProp<'row> ("rowSelection", s.ToString().ToLower()) + + static member inline isRowSelectable(callback: 'row -> bool) = + agGridProp<'row> ("isRowSelectable" ==> fun x -> x?data |> callback) + + static member inline suppressRowClickSelection(v: bool) = + agGridProp<'row> ("suppressRowClickSelection" ==> v) + + static member inline rowHeight(h: int) = agGridProp<'row> ("rowHeight", h) + static member inline immutableData(v: bool) = agGridProp<'row> ("immutableData", v) + /// Converts your data to a JS array to populate the grid. (This is less efficient than passing an array.) - static member inline rowData (data:'row seq) = agGridProp<'row>("rowData", Seq.toArray data) - static member inline rowData (data:'row array) = agGridProp<'row>("rowData", data) - static member inline rowDragManaged (v:bool) = agGridProp<'row>("rowDragManaged" ==> v) - static member inline defaultColDef (defaults:IColumnDefProp<'row, 'value> seq) = agGridProp<'row>("defaultColDef", defaults |> unbox<_ seq> |> createObj) - static member onColumnGroupOpened (callback:_ -> unit) = // This can't be inline otherwise Fable produces invalid JS - let onColumnGroupOpened = fun ev -> - {| AutoSizeGroupColumns = fun () -> - // Runs the column autoSize in a 0ms timeout so that the cellRendererFramework cells render - // before the grid calculates how large each cell is - JS.setTimeout (fun () -> - let colIds = ev?columnGroup?children |> Array.map (fun x -> x?colId) - ev?columnApi?autoSizeColumns(colIds)) 0 |> ignore |} - |> callback - agGridProp<'row>("onColumnGroupOpened", onColumnGroupOpened) - - static member inline paginationPageSize (pageSize:int) = agGridProp<'row>("paginationPageSize", pageSize) - static member inline paginationAutoPageSize (v:bool) = agGridProp<'row>("paginationAutoPageSize", v) - static member inline pagination (v:bool) = agGridProp<'row>("pagination", v) - static member onGridReady (callback:_ -> unit) = // This can't be inline otherwise Fable produces invalid JS - let onGridReady = fun ev -> - {| AutoSizeAllColumns = - fun () -> - // Runs the column autoSize in a 0ms timeout so that the cellRendererFramework cells render - // before the grid calculates how large each cell is - JS.setTimeout (fun () -> - let colIds = ev?api?getColumns() |> Array.map (fun x -> x?colId) - ev?api?autoSizeColumns(colIds)) 0 |> ignore - Export = fun () -> ev?api?exportDataAsCsv(obj()) |} - |> callback - agGridProp<'row>("onGridReady", onGridReady) - - static member inline processDataFromClipboard (callback: IProcessDataFromClipboardParams<'row> -> string[][]) = agGridProp<'row>("processDataFromClipboard", callback) - static member inline enableRangeHandle (v: bool) = agGridProp<'row>("enableRangeHandle", v) - static member inline enableRangeSelection (v: bool) = agGridProp<'row>("enableRangeSelection", v) - static member inline pivotMode (v: bool) = agGridProp<'row>("pivotMode", v) - static member inline treeData (v: bool) = agGridProp<'row>("treeData", v) - static member inline suppressAggFuncInHeader (v: bool) = agGridProp<'row>("suppressAggFuncInHeader", v) - static member inline getContextMenuItems (callback : int -> int -> MenuItem list) = agGridProp<'row>("getContextMenuItems", fun x -> - let menuItems = callback x?node?rowIndex x?column?colId - [| - for item in menuItems do - match item with - | BuiltIn builtInItemName -> box builtInItemName - | Custom customMenuItem -> box customMenuItem - |]) - static member inline headerHeight height = agGridProp<'row>("headerHeight", height) - static member inline groupHeaderHeight height = agGridProp<'row>("groupHeaderHeight", height) + static member inline rowData(data: 'row seq) = + agGridProp<'row> ("rowData", Seq.toArray data) + + static member inline rowData(data: 'row array) = agGridProp<'row> ("rowData", data) + + static member inline rowDragManaged(v: bool) = + agGridProp<'row> ("rowDragManaged" ==> v) + + static member inline defaultColDef(defaults: IColumnDefProp<'row, 'value> seq) = + agGridProp<'row> ("defaultColDef", defaults |> unbox<_ seq> |> createObj) + + static member onColumnGroupOpened(callback: _ -> unit) = // This can't be inline otherwise Fable produces invalid JS + let onColumnGroupOpened = + fun ev -> + {| + AutoSizeGroupColumns = + fun () -> + // Runs the column autoSize in a 0ms timeout so that the cellRendererFramework cells render + // before the grid calculates how large each cell is + JS.setTimeout + (fun () -> + let colIds = ev?columnGroup?children |> Array.map (fun x -> x?colId) + ev?columnApi?autoSizeColumns colIds) + 0 + |> ignore + |} + |> callback + + agGridProp<'row> ("onColumnGroupOpened", onColumnGroupOpened) + + static member inline paginationPageSize(pageSize: int) = + agGridProp<'row> ("paginationPageSize", pageSize) + + static member inline paginationAutoPageSize(v: bool) = + agGridProp<'row> ("paginationAutoPageSize", v) + + static member inline pagination(v: bool) = agGridProp<'row> ("pagination", v) + + static member onGridReady(callback: _ -> unit) = // This can't be inline otherwise Fable produces invalid JS + let onGridReady = + fun ev -> + {| + AutoSizeAllColumns = + fun () -> + // Runs the column autoSize in a 0ms timeout so that the cellRendererFramework cells render + // before the grid calculates how large each cell is + JS.setTimeout + (fun () -> + let colIds = ev?api?getColumns () |> Array.map (fun x -> x?colId) + ev?api?autoSizeColumns colIds) + 0 + |> ignore + Export = fun () -> ev?api?exportDataAsCsv (obj ()) + |} + |> callback + + agGridProp<'row> ("onGridReady", onGridReady) + + static member inline processDataFromClipboard(callback: IProcessDataFromClipboardParams<'row> -> string[][]) = + agGridProp<'row> ("processDataFromClipboard", callback) + + static member inline enableRangeHandle(v: bool) = + agGridProp<'row> ("enableRangeHandle", v) + + static member inline enableRangeSelection(v: bool) = + agGridProp<'row> ("enableRangeSelection", v) + + static member inline pivotMode(v: bool) = agGridProp<'row> ("pivotMode", v) + static member inline treeData(v: bool) = agGridProp<'row> ("treeData", v) + + static member inline suppressAggFuncInHeader(v: bool) = + agGridProp<'row> ("suppressAggFuncInHeader", v) + + static member inline getContextMenuItems(callback: int -> int -> MenuItem list) = + agGridProp<'row> ( + "getContextMenuItems", + fun x -> + let menuItems = callback x?node?rowIndex x?column?colId + + [| + for item in menuItems do + match item with + | BuiltIn builtInItemName -> box builtInItemName + | Custom customMenuItem -> box customMenuItem + |] + ) + + static member inline headerHeight height = + agGridProp<'row> ("headerHeight", height) + + static member inline groupHeaderHeight height = + agGridProp<'row> ("groupHeaderHeight", height) + [] - static member inline onCellFocused callback = agGridProp<'row>("onCellFocused", fun x -> callback (int x?rowIndex) (int x?column?colId)) - static member inline onCellFocused callback = agGridProp<'row>("onCellFocused", fun (e: ICellFocusedEvent<'row>) -> callback e) - static member inline onRangeSelectionChanged callback = agGridProp<'row>("onRangeSelectionChanged", fun x -> - let selectedRange = x?api?getCellRanges()?at(0) - let startRow = selectedRange?startRow?rowIndex - let startColumn = selectedRange?columns?at(0)?colId - let endRow = selectedRange?endRow?rowIndex - let endColumn = selectedRange?columns?at(selectedRange?columns?length-1)?colId - - callback startRow startColumn endRow endColumn) - static member inline popupParent parent = agGridProp<'row>("popupParent", parent) - static member inline processDataFromClipboard (callback : string[][] -> string[][]) = agGridProp<'row>("processDataFromClipboard", fun x -> callback x?data) - static member inline stopEditingWhenCellsLoseFocus (v: bool) = agGridProp<'row>("stopEditingWhenCellsLoseFocus", v) - static member inline stopEditingWhenGridLosesFocus (v: bool) = agGridProp<'row>("stopEditingWhenGridLosesFocus", v) - static member inline suppressClipboardApi (v: bool) = agGridProp<'row>("suppressClipboardApi", v) - static member inline suppressCopyRowsToClipboard (v: bool) = agGridProp<'row>("suppressCopyRowsToClipboard", v) - static member inline suppressCopySingleCellRanges (v: bool) = agGridProp<'row>("suppressCopySingleCellRanges", v) - static member inline suppressMultiRangeSelection (v: bool) = agGridProp<'row>("suppressMultiRangeSelection", v) - static member inline suppressRowHoverHighlight (v: bool) = agGridProp<'row>("suppressRowHoverHighlight", v) - static member inline suppressScrollOnNewData (v: bool) = agGridProp<'row>("suppressScrollOnNewData", v) - - static member inline key (v:string) = agGridProp<'row> (prop.key v) - static member inline key (v:int) = agGridProp<'row> (prop.key v) - static member inline key (v:System.Guid) = agGridProp<'row> (prop.key v) - - static member inline dataTypeDefinitions (v: obj) = agGridProp<'row>("dataTypeDefinitions", v) - static member inline enableFillHandle (v: bool) = agGridProp<'row>("enableFillHandle", v) - static member inline rowGroupPanelShow (v: RowGroupPanelShow) = agGridProp<'row>("rowGroupPanelShow", v.RowGroupPanelShowText) - static member inline groupDisplayType (v: RowGroupingDisplayType) = agGridProp<'row>("groupDisplayType", v.RowGroupingDisplayTypeText) - - static member inline undoRedoCellEditing (v: bool) = agGridProp<'row>("undoRedoCellEditing", v) - static member inline undoRedoCellEditingLimit (v: int) = agGridProp<'row>("undoRedoCellEditingLimit", v) - - static member inline grid (props: IAgGridProp<'row> seq) = Interop.reactApi.createElement (agGrid, createObj !!props) + static member inline onCellFocused callback = + agGridProp<'row> ("onCellFocused", (fun x -> callback (int x?rowIndex) (int x?column?colId))) + + static member inline onCellFocused callback = + agGridProp<'row> ("onCellFocused", (fun (e: ICellFocusedEvent<'row>) -> callback e)) + + // Removed because Fantomas can't handle, it's quite a niche feature, and the implementation is quite weird! + // https://github.com/fsprojects/fantomas/issues/3086 + // static member inline onRangeSelectionChanged callback = agGridProp<'row>("onRangeSelectionChanged", fun x -> + // let selectedRange = x?api?getCellRanges()?at(0) + // let startRow = selectedRange?startRow?rowIndex + // let startColumn = selectedRange?columns?at(0)?colId + // let endRow = selectedRange?endRow?rowIndex + // let endColumn = selectedRange?columns?at(selectedRange?columns?length-1)?colId + // + // callback startRow startColumn endRow endColumn) + + static member inline popupParent parent = + agGridProp<'row> ("popupParent", parent) + + static member inline processDataFromClipboard(callback: string[][] -> string[][]) = + agGridProp<'row> ("processDataFromClipboard", (fun x -> callback x?data)) + + static member inline stopEditingWhenCellsLoseFocus(v: bool) = + agGridProp<'row> ("stopEditingWhenCellsLoseFocus", v) + + static member inline stopEditingWhenGridLosesFocus(v: bool) = + agGridProp<'row> ("stopEditingWhenGridLosesFocus", v) + + static member inline suppressClipboardApi(v: bool) = + agGridProp<'row> ("suppressClipboardApi", v) + + static member inline suppressCopyRowsToClipboard(v: bool) = + agGridProp<'row> ("suppressCopyRowsToClipboard", v) + + static member inline suppressCopySingleCellRanges(v: bool) = + agGridProp<'row> ("suppressCopySingleCellRanges", v) + + static member inline suppressMultiRangeSelection(v: bool) = + agGridProp<'row> ("suppressMultiRangeSelection", v) + + static member inline suppressRowHoverHighlight(v: bool) = + agGridProp<'row> ("suppressRowHoverHighlight", v) + + static member inline suppressScrollOnNewData(v: bool) = + agGridProp<'row> ("suppressScrollOnNewData", v) + + static member inline key(v: string) = agGridProp<'row> (prop.key v) + static member inline key(v: int) = agGridProp<'row> (prop.key v) + static member inline key(v: Guid) = agGridProp<'row> (prop.key v) + + static member inline dataTypeDefinitions(v: obj) = + agGridProp<'row> ("dataTypeDefinitions", v) + + static member inline enableFillHandle(v: bool) = + agGridProp<'row> ("enableFillHandle", v) + + static member inline rowGroupPanelShow(v: RowGroupPanelShow) = + agGridProp<'row> ("rowGroupPanelShow", v.RowGroupPanelShowText) + + static member inline groupDisplayType(v: RowGroupingDisplayType) = + agGridProp<'row> ("groupDisplayType", v.RowGroupingDisplayTypeText) + + static member inline undoRedoCellEditing(v: bool) = + agGridProp<'row> ("undoRedoCellEditing", v) + + static member inline undoRedoCellEditingLimit(v: int) = + agGridProp<'row> ("undoRedoCellEditingLimit", v) + + static member inline grid(props: IAgGridProp<'row> seq) = + Interop.reactApi.createElement (agGrid, createObj !!props) From 30601f898e9e7749a56891163b39ece3b4740f9e Mon Sep 17 00:00:00 2001 From: Matt Gallagher Date: Fri, 24 May 2024 12:46:55 +0100 Subject: [PATCH 05/27] Link to React Grid docs in doc comments --- src/AgGrid.fs | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/src/AgGrid.fs b/src/AgGrid.fs index e0824f2..c3a466a 100644 --- a/src/AgGrid.fs +++ b/src/AgGrid.fs @@ -8,7 +8,7 @@ open Feliz let agGrid: obj = import "AgGridReact" "ag-grid-react" -// https://www.ag-grid.com/javascript-data-grid/row-object/ +/// See https://www.ag-grid.com/react-data-grid/row-object/. [] type IRowNode<'row> = { id: string @@ -34,7 +34,7 @@ type ICellRange = { member this.startRowIndex: int = this.startRow?rowIndex member this.endRowIndex: int = this.endRow?rowIndex -// https://www.ag-grid.com/javascript-data-grid/grid-interface/#grid-api +/// See https://www.ag-grid.com/react-data-grid/grid-interface/#grid-api. [] type IGridApi<'row> = abstract copyToClipboard: unit -> unit @@ -45,7 +45,7 @@ type IGridApi<'row> = abstract getSelectedNodes: unit -> IRowNode<'row>[] abstract getCellRanges: unit -> ICellRange[] -// https://www.ag-grid.com/javascript-data-grid/column-object/ +/// See https://www.ag-grid.com/react-data-grid/column-object/. [] type IColumn = { getColId: unit -> string } @@ -59,8 +59,8 @@ type IColumnDef<'row> = interface end [] module CallbackParams = - // https://www.ag-grid.com/react-data-grid/column-properties/#reference-editing-valueSetter - // https://www.ag-grid.com/javascript-data-grid//column-properties/#reference-editing-valueParser + /// See https://www.ag-grid.com/react-data-grid/column-properties/#reference-editing-valueSetter. + /// See https://www.ag-grid.com/react-data-grid/column-properties/#reference-editing-valueParser. [] type IValueChangedParams<'row, 'value> = { oldValue: 'value @@ -74,7 +74,7 @@ module CallbackParams = member this.rowIndex = this.node.rowIndex - // https://www.ag-grid.com/javascript-data-grid/component-cell-editor/#reference-ICellEditorParams + /// See https://www.ag-grid.com/react-data-grid/cell-editors/#custom-components. [] type IValueParams<'row, 'value> = { value: 'value @@ -86,7 +86,7 @@ module CallbackParams = rowIndex: int } - // https://www.ag-grid.com/javascript-data-grid/grid-events/#reference-selection-cellFocused + /// See https://www.ag-grid.com/react-data-grid/grid-events/#reference-selection-cellFocused. [] type ICellFocusedEvent<'row> = { api: IGridApi<'row> @@ -95,7 +95,7 @@ module CallbackParams = isFullWidthCell: bool } - // https://www.ag-grid.com/javascript-data-grid//grid-options/#reference-rowModels-getRowId + /// See https://www.ag-grid.com/react-data-grid//grid-options/#reference-rowModels-getRowId. [] type IGetRowIdParams<'row> = { data: 'row From dd170b904f03ccd094cd67a6fd7d9aca2ff93777 Mon Sep 17 00:00:00 2001 From: Matt Gallagher Date: Fri, 24 May 2024 12:47:38 +0100 Subject: [PATCH 06/27] Improve comments for AgGrid.field --- src/AgGrid.fs | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/src/AgGrid.fs b/src/AgGrid.fs index c3a466a..c8c3069 100644 --- a/src/AgGrid.fs +++ b/src/AgGrid.fs @@ -356,11 +356,10 @@ type ColumnDef<'row, 'value> = static member inline field(v: string) = columnDefProp<'row, 'value> ("field" ==> v) + /// Usage: `ColumnDef.field _.FieldName` or `ColumnDef.field (fun x -> x.FieldName)` static member inline field(f: 'row -> _) = - // usage: `AgGrid.field _.FirstName` or `AgGrid.field (fun x -> x.FirstName)` - // Result = "FirstName" - // Get everthing after first '.' let idxOfFirstDot = (string f).IndexOf('.') + // `ColumnDef.field _.FirstName` and `ColumnDef.field (fun x -> x.FirstName)` both result in "FirstName". let field = (string f).Substring(idxOfFirstDot + 1) columnDefProp<'row, 'value> ("field" ==> field) From 5acdcce35c0435a77b1b0c07ed9ac4d24192be2b Mon Sep 17 00:00:00 2001 From: Matt Gallagher Date: Fri, 28 Jun 2024 14:26:04 +0100 Subject: [PATCH 07/27] Fix onColumnGroupOpened --- src/AgGrid.fs | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/src/AgGrid.fs b/src/AgGrid.fs index c8c3069..f2485f5 100644 --- a/src/AgGrid.fs +++ b/src/AgGrid.fs @@ -559,12 +559,17 @@ type AgGrid<'row> = {| AutoSizeGroupColumns = fun () -> - // Runs the column autoSize in a 0ms timeout so that the cellRendererFramework cells render - // before the grid calculates how large each cell is + // Runs the column autoSize in a 0ms timeout so that the cellRenderer cells render before + // the grid calculates how large each cell is JS.setTimeout (fun () -> - let colIds = ev?columnGroup?children |> Array.map (fun x -> x?colId) - ev?columnApi?autoSizeColumns colIds) + let colIds = + ev?columnGroups + |> Seq.head + |> fun cg -> cg?children + |> Array.map (fun x -> x?colId) + + ev?api?autoSizeColumns colIds) 0 |> ignore |} From cbb0102e9a7504d0518d32999071c1751ea85be6 Mon Sep 17 00:00:00 2001 From: Matt Gallagher Date: Fri, 28 Jun 2024 14:27:26 +0100 Subject: [PATCH 08/27] Update demo code to use new API --- demo/src/Components.fs | 97 +++++++++++++++++++++++------------------- 1 file changed, 53 insertions(+), 44 deletions(-) diff --git a/demo/src/Components.fs b/demo/src/Components.fs index 0c08cca..242bcaa 100644 --- a/demo/src/Components.fs +++ b/demo/src/Components.fs @@ -9,7 +9,6 @@ open Thoth.Fetch open Thoth.Json open Fable.Core - let citDarkBlue = "#102035" type LinkData = { Text: string; Href: string } @@ -127,12 +126,15 @@ type Olympian = { Total: int } +importAll "ag-grid-community/styles/ag-grid.css" +importAll "ag-grid-community/styles/ag-theme-balham.css" + [] let Demo () = - let (olympicData, setOlympicData) = React.useState (None) + let olympicData, setOlympicData = React.useState None let getData () : JS.Promise = promise { - let url = sprintf "https://www.ag-grid.com/example-assets/olympic-winners.json" + let url = "https://www.ag-grid.com/example-assets/olympic-winners.json" return! Fetch.get (url, caseStrategy = CamelCase) } @@ -187,30 +189,32 @@ let Demo () = AgGrid.enableCellTextSelection true AgGrid.ensureDomOrder true AgGrid.columnDefs [ - ColumnDef.create [ + ColumnDef.create [ ColumnDef.filter RowFilter.Text ColumnDef.headerName "Athlete (editable)" ColumnDef.valueGetter (fun x -> x.Athlete) ColumnDef.editable (fun _ _ -> true) - ColumnDef.valueSetter (fun newValue _ row -> - updateRowAthleteName newValue row) + ColumnDef.valueSetter (fun valueChangedParams -> + updateRowAthleteName + valueChangedParams.newValue + valueChangedParams.data) ] - ColumnDef.create [ + ColumnDef.create [ ColumnDef.filter RowFilter.Number ColumnDef.columnType ColumnType.NumericColumn ColumnDef.headerName "Age" ColumnDef.valueGetter (fun x -> x.Age) - ColumnDef.valueFormatter (fun age _ -> - match age with - | Some age -> $"{age} years" + ColumnDef.valueFormatter (fun valueParams -> + match valueParams.value with + | Some age -> $"%i{age} years" | None -> "Unknown") ] - ColumnDef.create [ + ColumnDef.create [ ColumnDef.filter RowFilter.Text ColumnDef.headerName "Country" ColumnDef.valueGetter (fun x -> x.Country) ] - ColumnDef.create [ + ColumnDef.create [ ColumnDef.filter RowFilter.Date ColumnDef.headerName "Date" ColumnDef.valueGetter (fun x -> @@ -218,9 +222,11 @@ let Demo () = |> function | [| d; m; y |] -> DateTime(int y, int m, int d) | _ -> DateTime.MinValue) - ColumnDef.valueFormatter (fun d _ -> d.ToShortDateString()) + ColumnDef.valueFormatter (fun valueParams -> + let date: DateTime = valueParams.value + date.ToShortDateString()) ] - ColumnDef.create [ + ColumnDef.create [ ColumnDef.filter RowFilter.Text ColumnDef.headerName "Sport" ColumnDef.valueGetter (fun x -> x.Sport) @@ -230,36 +236,36 @@ let Demo () = ColumnGroup.marryChildren true ColumnGroup.openByDefault true ] [ - ColumnDef.create [ + ColumnDef.create [ ColumnDef.filter RowFilter.Number ColumnDef.headerName "Total" ColumnDef.columnType ColumnType.NumericColumn ColumnDef.valueGetter (fun x -> x.Total) - ColumnDef.cellRenderer (fun x _ -> + ColumnDef.cellRenderer (fun rendererParams -> Html.span [ Html.span [ prop.style [ style.fontSize 9 ] prop.children [ Html.text "🏅" ] ] - Html.textf "%i" x + Html.text $"%i{rendererParams.value}" ]) ColumnDef.columnGroupShow true ] - ColumnDef.create [ + ColumnDef.create [ ColumnDef.filter RowFilter.Number ColumnDef.headerName "Gold" ColumnDef.columnType ColumnType.NumericColumn ColumnDef.valueGetter (fun x -> x.Gold) ColumnDef.columnGroupShow false ] - ColumnDef.create [ + ColumnDef.create [ ColumnDef.filter RowFilter.Number ColumnDef.headerName "Silver" ColumnDef.columnType ColumnType.NumericColumn ColumnDef.valueGetter (fun x -> x.Silver) ColumnDef.columnGroupShow false ] - ColumnDef.create [ + ColumnDef.create [ ColumnDef.filter RowFilter.Number ColumnDef.headerName "Bronze" ColumnDef.columnType ColumnType.NumericColumn @@ -297,16 +303,16 @@ type Olympian = Bronze: int Total: int } +importAll "ag-grid-community/styles/ag-grid.css" +importAll "ag-grid-community/styles/ag-theme-balham.css" + Html.div [ prop.className ThemeClass.Balham prop.children [ AgGrid.grid [ AgGrid.rowData olympicData AgGrid.pagination true - AgGrid.defaultColDef [ - ColumnDef.resizable true - ColumnDef.sortable true - ] + AgGrid.defaultColDef [ ColumnDef.resizable true; ColumnDef.sortable true ] AgGrid.domLayout AutoHeight AgGrid.paginationPageSize 20 AgGrid.onColumnGroupOpened (fun x -> x.AutoSizeGroupColumns()) @@ -315,29 +321,32 @@ Html.div [ AgGrid.enableCellTextSelection true AgGrid.ensureDomOrder true AgGrid.columnDefs [ - ColumnDef.create [ + ColumnDef.create [ ColumnDef.filter RowFilter.Text ColumnDef.headerName "Athlete (editable)" ColumnDef.valueGetter (fun x -> x.Athlete) ColumnDef.editable (fun _ _ -> true) - ColumnDef.valueSetter (fun newValue _ row -> updateRowAthleteName newValue row) + ColumnDef.valueSetter (fun valueChangedParams -> + updateRowAthleteName + valueChangedParams.newValue + valueChangedParams.data) ] - ColumnDef.create [ + ColumnDef.create [ ColumnDef.filter RowFilter.Number ColumnDef.columnType ColumnType.NumericColumn ColumnDef.headerName "Age" ColumnDef.valueGetter (fun x -> x.Age) - ColumnDef.valueFormatter (fun age _ -> - match age with - | Some age -> $"{age} years" - | None -> "Unknown" ) + ColumnDef.valueFormatter (fun valueParams -> + match valueParams.value with + | Some age -> $"%i{age} years" + | None -> "Unknown") ] - ColumnDef.create [ + ColumnDef.create [ ColumnDef.filter RowFilter.Text ColumnDef.headerName "Country" ColumnDef.valueGetter (fun x -> x.Country) ] - ColumnDef.create [ + ColumnDef.create [ ColumnDef.filter RowFilter.Date ColumnDef.headerName "Date" ColumnDef.valueGetter (fun x -> @@ -345,9 +354,11 @@ Html.div [ |> function | [| d; m; y |] -> DateTime(int y, int m, int d) | _ -> DateTime.MinValue) - ColumnDef.valueFormatter (fun d _ -> d.ToShortDateString()) + ColumnDef.valueFormatter (fun valueParams -> + let date: DateTime = valueParams.value + date.ToShortDateString()) ] - ColumnDef.create [ + ColumnDef.create [ ColumnDef.filter RowFilter.Text ColumnDef.headerName "Sport" ColumnDef.valueGetter (fun x -> x.Sport) @@ -357,38 +368,36 @@ Html.div [ ColumnGroup.marryChildren true ColumnGroup.openByDefault true ] [ - ColumnDef.create [ + ColumnDef.create [ ColumnDef.filter RowFilter.Number ColumnDef.headerName "Total" ColumnDef.columnType ColumnType.NumericColumn ColumnDef.valueGetter (fun x -> x.Total) - ColumnDef.cellRenderer (fun x _ -> + ColumnDef.cellRenderer (fun rendererParams -> Html.span [ Html.span [ prop.style [ style.fontSize 9 ] - prop.children [ - Html.text "🏅" - ] + prop.children [ Html.text "🏅" ] ] - Html.textf "%i" x + Html.text $"%i{rendererParams.value}" ]) ColumnDef.columnGroupShow true ] - ColumnDef.create [ + ColumnDef.create [ ColumnDef.filter RowFilter.Number ColumnDef.headerName "Gold" ColumnDef.columnType ColumnType.NumericColumn ColumnDef.valueGetter (fun x -> x.Gold) ColumnDef.columnGroupShow false ] - ColumnDef.create [ + ColumnDef.create [ ColumnDef.filter RowFilter.Number ColumnDef.headerName "Silver" ColumnDef.columnType ColumnType.NumericColumn ColumnDef.valueGetter (fun x -> x.Silver) ColumnDef.columnGroupShow false ] - ColumnDef.create [ + ColumnDef.create [ ColumnDef.filter RowFilter.Number ColumnDef.headerName "Bronze" ColumnDef.columnType ColumnType.NumericColumn From 94ebf5f73c712eb6af9721e7a1863d26bbf4374f Mon Sep 17 00:00:00 2001 From: Matt Gallagher Date: Fri, 28 Jun 2024 14:24:44 +0100 Subject: [PATCH 09/27] Refactor property implementation --- src/AgGrid.fs | 17 ++++++++++------- 1 file changed, 10 insertions(+), 7 deletions(-) diff --git a/src/AgGrid.fs b/src/AgGrid.fs index f2485f5..914e1fb 100644 --- a/src/AgGrid.fs +++ b/src/AgGrid.fs @@ -57,6 +57,8 @@ let columnDefProp<'row, 'value> = unbox> [] type IColumnDef<'row> = interface end +let columnDef<'row> = unbox> + [] module CallbackParams = /// See https://www.ag-grid.com/react-data-grid/column-properties/#reference-editing-valueSetter. @@ -262,7 +264,7 @@ let CellRendererComponent<'row, 'value> [] type ColumnDef<'row, 'value> = - static member inline create(props: IColumnDefProp<'row, 'value> seq) = createObj !!props :?> IColumnDef<'row> + static member inline create(props: IColumnDefProp<'row, 'value> seq) = createObj !!props |> columnDef<'row> static member inline aggFunc(v: AggregateFunction) = columnDefProp<'row, 'value> ("aggFunc" ==> v.AggregateText) @@ -463,11 +465,12 @@ type ColumnGroup<'row> = columnGroupDefProp<'row> ("openByDefault" ==> v) static member inline create (props: seq>) (children: seq>) = - props - |> Seq.append [ (columnGroupDefProp<'row> ("children" ==> Seq.toArray children)) ] - |> unbox<_ seq> - |> createObj - |> unbox> + let combinedProps = seq { + yield! props + columnGroupDefProp<'row> ("children" ==> Seq.toArray children) + } + + createObj !!combinedProps |> columnDef<'row> [] type IAgGridProp<'row> = interface end @@ -482,7 +485,7 @@ type AgGrid<'row> = agGridProp<'row> ("alwaysShowVerticalScroll" ==> v) static member inline columnDefs(columns: IColumnDef<'row> seq) = - agGridProp<'row> ("columnDefs", columns |> unbox |> Seq.toArray) + agGridProp<'row> ("columnDefs", Seq.toArray !!columns) static member inline copyHeadersToClipboard(v: bool) = agGridProp<'row> ("copyHeadersToClipboard" ==> v) From b0ef4fb6e9b6bc61c6853011e2cb3c1c1278da04 Mon Sep 17 00:00:00 2001 From: Matt Gallagher Date: Fri, 28 Jun 2024 14:33:12 +0100 Subject: [PATCH 10/27] Remove commented out code --- src/AgGrid.fs | 8 +------- 1 file changed, 1 insertion(+), 7 deletions(-) diff --git a/src/AgGrid.fs b/src/AgGrid.fs index 914e1fb..caa256d 100644 --- a/src/AgGrid.fs +++ b/src/AgGrid.fs @@ -292,13 +292,9 @@ type ColumnDef<'row, 'value> = static member cellRendererFramework _ = failwith "cellRendererFramework isn't supported in the latest version of AgGrid. Use cellRenderer instead" - // Removed to resolve type inference issue with multiple overloads - //static member cellRenderer' (render: 'value -> 'row -> ReactElement) = columnDefProp<'row, 'value> ("cellRenderer" ==> fun (p: ICellRendererParams<'row, 'value>) -> CellRendererComponentSimple(render, p.value, p.data)) static member cellRenderer(render: ICellRendererParams<'row, 'value> -> ReactElement) = columnDefProp<'row, 'value> ("cellRenderer" ==> fun p -> CellRendererComponent(render, p)) - // Removed to resolve type inference issue with multiple overloads - //static member cellEditor' (render: 'value -> 'row -> ReactElement) = columnDefProp<'row, 'value> ("cellEditor" ==> fun (p: ICellRendererParams<'row, 'value>) -> CellRendererComponentSimple(render, p.value, p.data)) static member cellEditor(render: ICellRendererParams<'row, 'value> -> ReactElement) = columnDefProp<'row, 'value> ("cellEditor" ==> fun p -> CellRendererComponent(render, p)) @@ -354,7 +350,7 @@ type ColumnDef<'row, 'value> = static member inline enableCellChangeFlash(v: bool) = columnDefProp<'row, 'value> ("enableCellChangeFlash" ==> v) - //static member inline field (v:'a -> string) = columnDefProp<'row, 'value> ("field" ==> v (unbox null)) + static member inline field(v: string) = columnDefProp<'row, 'value> ("field" ==> v) @@ -428,8 +424,6 @@ type ColumnDef<'row, 'value> = static member inline suppressMovable = columnDefProp<'row, 'value> ("suppressMovable" ==> true) - // Removed to resolve type inference issue with multiple overloads - //static member inline valueFormatter (callback:'value -> 'row -> string) = columnDefProp<'row, 'value> ("valueFormatter" ==> (fun (p: IValueParams<'row, 'value>) -> callback p.value p.data)) static member inline valueFormatter(callback: IValueParams<'row, 'value> -> string) = columnDefProp<'row, 'value> ("valueFormatter" ==> callback) From 3fea3bb7cb518a688c3940431b66e4b095b1efe3 Mon Sep 17 00:00:00 2001 From: Matt Gallagher Date: Fri, 28 Jun 2024 14:35:57 +0100 Subject: [PATCH 11/27] Reinstate code (removed because of fantomas error) --- .config/dotnet-tools.json | 2 +- README.md | 6 ------ src/AgGrid.fs | 22 ++++++++++++---------- 3 files changed, 13 insertions(+), 17 deletions(-) diff --git a/.config/dotnet-tools.json b/.config/dotnet-tools.json index a079483..b745001 100644 --- a/.config/dotnet-tools.json +++ b/.config/dotnet-tools.json @@ -21,7 +21,7 @@ ] }, "fantomas": { - "version": "6.3.4", + "version": "6.3.9", "commands": [ "fantomas" ] diff --git a/README.md b/README.md index 5997a94..f88922c 100644 --- a/README.md +++ b/README.md @@ -29,12 +29,6 @@ importAll "ag-grid-community/styles/ag-grid.css" importAll "ag-grid-community/styles/ag-theme-balham.css" ``` -##### AgGrid.onRangeSelectionChanged callback removed - -Fantomas was erroring when trying to format our previous implementation. We'll reinstate it once we have an -implementation that Fantomas can handle. Raise an issue if this is an important feature for you and we'll try to get -something working soon! - ## Installation Run `femto install Feliz.AgGrid` from inside your project directory. diff --git a/src/AgGrid.fs b/src/AgGrid.fs index caa256d..e88da5e 100644 --- a/src/AgGrid.fs +++ b/src/AgGrid.fs @@ -644,16 +644,18 @@ type AgGrid<'row> = static member inline onCellFocused callback = agGridProp<'row> ("onCellFocused", (fun (e: ICellFocusedEvent<'row>) -> callback e)) - // Removed because Fantomas can't handle, it's quite a niche feature, and the implementation is quite weird! - // https://github.com/fsprojects/fantomas/issues/3086 - // static member inline onRangeSelectionChanged callback = agGridProp<'row>("onRangeSelectionChanged", fun x -> - // let selectedRange = x?api?getCellRanges()?at(0) - // let startRow = selectedRange?startRow?rowIndex - // let startColumn = selectedRange?columns?at(0)?colId - // let endRow = selectedRange?endRow?rowIndex - // let endColumn = selectedRange?columns?at(selectedRange?columns?length-1)?colId - // - // callback startRow startColumn endRow endColumn) + static member inline onRangeSelectionChanged callback = + agGridProp<'row> ( + "onRangeSelectionChanged", + fun x -> + let selectedRange = x?api?getCellRanges ()?at 0 + let startRow = selectedRange?startRow?rowIndex + let startColumn = selectedRange?columns?at 0?colId + let endRow = selectedRange?endRow?rowIndex + let endColumn = selectedRange?columns?at (selectedRange?columns?length - 1)?colId + + callback startRow startColumn endRow endColumn + ) static member inline popupParent parent = agGridProp<'row> ("popupParent", parent) From 913165158b70d83b592852842656d56e49373d8d Mon Sep 17 00:00:00 2001 From: Matt Gallagher Date: Fri, 28 Jun 2024 14:47:31 +0100 Subject: [PATCH 12/27] Add LicenseManager.setLicenseKey --- src/AgGrid.fs | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/src/AgGrid.fs b/src/AgGrid.fs index e88da5e..bfb8ad5 100644 --- a/src/AgGrid.fs +++ b/src/AgGrid.fs @@ -6,8 +6,16 @@ open Fable.Core open Fable.Core.JsInterop open Feliz +// Suppress unused value warnings - they are often necessary for Fable bindings. +#nowarn "1182" + let agGrid: obj = import "AgGridReact" "ag-grid-react" +[] +[] +type LicenseManager = + static member setLicenseKey(key: string) : unit = jsNative + /// See https://www.ag-grid.com/react-data-grid/row-object/. [] type IRowNode<'row> = { From 2eb5cace694aed49e7ff891c572ddae53f26ebb3 Mon Sep 17 00:00:00 2001 From: Matt Gallagher Date: Fri, 28 Jun 2024 15:06:54 +0100 Subject: [PATCH 13/27] Document API changes in README's migration section --- README.md | 25 +++++++++++++++++++++++++ 1 file changed, 25 insertions(+) diff --git a/README.md b/README.md index f88922c..90cfa4d 100644 --- a/README.md +++ b/README.md @@ -29,6 +29,31 @@ importAll "ag-grid-community/styles/ag-grid.css" importAll "ag-grid-community/styles/ag-theme-balham.css" ``` +##### Use new API + +Many properties have been updated to more closely reflect the AG Grid docs. In particular, functions like +valueFormatter, valueSetter and cellRenderer now take single-parameter functions, with that parameter having properties +on it allowing you to access the data that you need. This makes it easier for you to get started from the AG Grid docs. + +For example, rather than `ColumnDef.cellRenderer` giving you the value in the cell, you are now given a params object +that has a `.value` field. + +```diff +- ColumnDef.cellRenderer (fun x _ -> ++ ColumnDef.cellRenderer (fun rendererParams -> + Html.span [ + Html.span [ + prop.style [ style.fontSize 9 ] + prop.children [ Html.text "🏅" ] + ] +- Html.textf "%i" x ++ Html.text $"%i{rendererParams.value}" + ]) +``` + +You can see more examples of the required changes in [Git +commit `cbb0102`](https://github.com/CompositionalIT/feliz-ag-grid/commit/cbb0102e9a7504d0518d32999071c1751ea85be6). + ## Installation Run `femto install Feliz.AgGrid` from inside your project directory. From 56db3fc1563372630ac03458b6c5d02a01387cb4 Mon Sep 17 00:00:00 2001 From: Matt Gallagher Date: Fri, 28 Jun 2024 16:04:45 +0100 Subject: [PATCH 14/27] Improve type safety and type inference of wrapper Ensures that all props for a single column def assume the same underlying value. This means that it's not possible to mix and match types (which would be a bug), and means that the complier can infer types for you (meaning fewer type annotations). --- demo/src/Components.fs | 3 +- src/AgGrid.fs | 1446 ++++++++++++++++++++-------------------- 2 files changed, 726 insertions(+), 723 deletions(-) diff --git a/demo/src/Components.fs b/demo/src/Components.fs index 242bcaa..2a9333a 100644 --- a/demo/src/Components.fs +++ b/demo/src/Components.fs @@ -223,8 +223,7 @@ let Demo () = | [| d; m; y |] -> DateTime(int y, int m, int d) | _ -> DateTime.MinValue) ColumnDef.valueFormatter (fun valueParams -> - let date: DateTime = valueParams.value - date.ToShortDateString()) + valueParams.value.ToShortDateString()) ] ColumnDef.create [ ColumnDef.filter RowFilter.Text diff --git a/src/AgGrid.fs b/src/AgGrid.fs index bfb8ad5..d10a565 100644 --- a/src/AgGrid.fs +++ b/src/AgGrid.fs @@ -1,721 +1,725 @@ -module Feliz.AgGrid - -open System - -open Fable.Core -open Fable.Core.JsInterop -open Feliz - -// Suppress unused value warnings - they are often necessary for Fable bindings. -#nowarn "1182" - -let agGrid: obj = import "AgGridReact" "ag-grid-react" - -[] -[] -type LicenseManager = - static member setLicenseKey(key: string) : unit = jsNative - -/// See https://www.ag-grid.com/react-data-grid/row-object/. -[] -type IRowNode<'row> = { - id: string - data: 'row - updateData: 'row -> unit - setData: 'row -> unit - setSelected: bool -> unit - rowIndex: int - rowTop: int - displayed: bool - isHovered: bool - isFullWidthCell: bool - isSelected: bool -} - -[] -type ICellRange = { - id: string - startRow: obj - endRow: obj -} with - - member this.startRowIndex: int = this.startRow?rowIndex - member this.endRowIndex: int = this.endRow?rowIndex - -/// See https://www.ag-grid.com/react-data-grid/grid-interface/#grid-api. -[] -type IGridApi<'row> = - abstract copyToClipboard: unit -> unit - abstract pasteFromClipboard: unit -> unit - abstract refreshCells: unit -> unit - abstract redrawRows: unit -> unit - abstract setGridOption: string -> obj -> unit - abstract getSelectedNodes: unit -> IRowNode<'row>[] - abstract getCellRanges: unit -> ICellRange[] - -/// See https://www.ag-grid.com/react-data-grid/column-object/. -[] -type IColumn = { getColId: unit -> string } - -[] -type IColumnDefProp<'row, 'value> = interface end - -let columnDefProp<'row, 'value> = unbox> - -[] -type IColumnDef<'row> = interface end - -let columnDef<'row> = unbox> - -[] -module CallbackParams = - /// See https://www.ag-grid.com/react-data-grid/column-properties/#reference-editing-valueSetter. - /// See https://www.ag-grid.com/react-data-grid/column-properties/#reference-editing-valueParser. - [] - type IValueChangedParams<'row, 'value> = { - oldValue: 'value - newValue: 'value - node: IRowNode<'row> - data: 'row - column: IColumn - colDef: IColumnDef<'row> - api: IGridApi<'row> - } with - - member this.rowIndex = this.node.rowIndex - - /// See https://www.ag-grid.com/react-data-grid/cell-editors/#custom-components. - [] - type IValueParams<'row, 'value> = { - value: 'value - data: 'row - node: IRowNode<'row> - colDef: IColumnDef<'row> - column: IColumn - api: IGridApi<'row> - rowIndex: int - } - - /// See https://www.ag-grid.com/react-data-grid/grid-events/#reference-selection-cellFocused. - [] - type ICellFocusedEvent<'row> = { - api: IGridApi<'row> - rowIndex: int - column: IColumn - isFullWidthCell: bool - } - - /// See https://www.ag-grid.com/react-data-grid//grid-options/#reference-rowModels-getRowId. - [] - type IGetRowIdParams<'row> = { - data: 'row - level: int - parentKeys: string[] - api: IGridApi<'row> - context: obj - } - - [] - type ICellRendererParams<'row, 'value> = { - value: 'value - data: 'row - node: IRowNode<'row> - colDef: IColumnDef<'row> - column: IColumn - api: IGridApi<'row> - rowIndex: int - } - - [] - type IPasteEvent<'row> = { - source: string - api: IGridApi<'row> - context: obj - ``type``: string - } - - [] - type IProcessDataFromClipboardParams<'row> = { - data: string[][] - api: IGridApi<'row> - context: obj - } - -type RowSelection = - | Single - | Multiple - -[] -type RowGroupingDisplayType = - | SingleColumn - | MultipleColumns - | GroupRows - | Custom - - member this.RowGroupingDisplayTypeText = - match this with - | SingleColumn -> "singleColumn" - | MultipleColumns -> "multipleColumns" - | GroupRows -> "groupRows" - | Custom -> "custom" - -[] -type RowGroupPanelShow = - | Always - | OnlyWhenGrouping - | Never - - member this.RowGroupPanelShowText = - match this with - | Always -> "always" - | OnlyWhenGrouping -> "onlyWhenGrouping" - | Never -> "never" - -[] -type RowFilter = - | Number - | Text - | Date - | Set - - member this.FilterText = sprintf "ag%OColumnFilter" this - -[] -type CellDataType = - | Text - | Number - | Date - | DateString - | Boolean - | Object - | Custom of string - - member this.CellDataTypeText = - match this with - | Text -> "text" - | Number -> "number" - | Date -> "date" - | DateString -> "dateString" - | Boolean -> "boolean" - | Object -> "object" - | Custom s -> s - -[] -type AgCellEditor = - | SelectCellEditor - | RichSelectCellEditor - | NumberCellEditor - | DateCellEditor - | DateStringCellEditor - | CheckboxCellEditor - | LargeTextCellEditor - | TextCellEditor - - member this.RichCellEditorText = sprintf "ag%O" this - -[] - -type AggregateFunction = - | Sum - | Min - | Max - | Count - | Avg - | First - | Last - - member this.AggregateText = (sprintf "%O" this).ToLower() - -type DOMLayout = - | Normal - | AutoHeight - | Print - - member this.LayoutText = - match this with - | Normal -> "normal" - | AutoHeight -> "autoHeight" - | Print -> "print" - -module ThemeClass = - let Alpine = "ag-theme-alpine" - let AlpineDark = "ag-theme-alpine-dark" - let Balham = "ag-theme-balham" - let BalhamDark = "ag-theme-balham-dark" - let Material = "ag-theme-material" - -type MenuItemDef = { - name: string - action: unit -> unit - shortcut: string - icon: obj //HtmlElement -} - -type MenuItem = - | BuiltIn of string - | Custom of MenuItemDef - -type ColumnType = - | RightAligned - | NumericColumn - -let openClosed = - function - | true -> "open" - | false -> "closed" - -[] -let CellRendererComponent<'row, 'value> - (render: ICellRendererParams<'row, 'value> -> ReactElement, p: ICellRendererParams<'row, 'value>) - = - render p - -[] -type ColumnDef<'row, 'value> = - static member inline create(props: IColumnDefProp<'row, 'value> seq) = createObj !!props |> columnDef<'row> - - static member inline aggFunc(v: AggregateFunction) = - columnDefProp<'row, 'value> ("aggFunc" ==> v.AggregateText) - - static member inline autoComparator = columnDefProp<'row, 'value> ("comparator" ==> compare) - - static member inline cellClass(setClass: 'value -> 'row -> #seq) = - columnDefProp<'row, 'value> ("cellClass" ==> fun p -> setClass p?value p?data |> Seq.toArray) - - static member inline cellClassRules(rules: (string * ('value -> 'row -> bool)) list) = - columnDefProp<'row, 'value> ( - "cellClassRules" - ==> (rules - |> List.map (fun (className, rule) -> className ==> fun p -> rule p?value p?data) - |> createObj) - ) - - static member cellDataType(v: bool) = - columnDefProp<'row, 'value> ("cellDataType" ==> v) - - static member cellDataType(v: CellDataType) = - columnDefProp<'row, 'value> ("cellDataType" ==> v.CellDataTypeText) - - [] - static member cellRendererFramework _ = - failwith "cellRendererFramework isn't supported in the latest version of AgGrid. Use cellRenderer instead" - - static member cellRenderer(render: ICellRendererParams<'row, 'value> -> ReactElement) = - columnDefProp<'row, 'value> ("cellRenderer" ==> fun p -> CellRendererComponent(render, p)) - - static member cellEditor(render: ICellRendererParams<'row, 'value> -> ReactElement) = - columnDefProp<'row, 'value> ("cellEditor" ==> fun p -> CellRendererComponent(render, p)) - - static member cellEditor(v: string) = - columnDefProp<'row, 'value> ("cellEditor" ==> v) - - static member cellEditor(v: AgCellEditor) = - columnDefProp<'row, 'value> ("cellEditor" ==> v.RichCellEditorText) - - static member cellEditorParams(v: string seq) = - columnDefProp<'row, 'value> ("cellEditorParams" ==> {| values = v |> Seq.toArray |}) - - static member cellEditorParams(v: obj) = - columnDefProp<'row, 'value> ("cellEditorParams" ==> v) - - static member cellEditorPopup(v: bool) = - columnDefProp<'row, 'value> ("cellEditorPopup" ==> v) - - static member inline cellStyle(setStyle: 'value -> 'row -> _) = - columnDefProp<'row, 'value> ("cellStyle" ==> fun p -> setStyle p?value p?data) - - static member inline checkboxSelection(v: bool) = - columnDefProp<'row, 'value> ("checkboxSelection" ==> v) - - static member inline colId(v: string) = - columnDefProp<'row, 'value> ("colId" ==> v) - - static member inline columnGroupShow(v: bool) = - columnDefProp<'row, 'value> ("columnGroupShow" ==> openClosed v) - - static member inline columnType ct = - columnDefProp<'row, 'value> ( - "type" - ==> match ct with - | RightAligned -> "rightAligned" - | NumericColumn -> "numericColumn" - ) - - static member inline comparator(callback: 'a -> 'a -> int) = - columnDefProp<'row, 'value> ("comparator" ==> fun a b -> callback a b) - - static member inline editable(callback: 'value -> 'row -> bool) = - columnDefProp<'row, 'value> ("editable" ==> fun p -> callback p?value p?data) - - static member inline editable(v: bool) = - columnDefProp<'row, 'value> ("editable" ==> v) - - static member inline equals(callback: 'value -> 'value -> bool) = - columnDefProp<'row, 'value> ("equals" ==> callback) - - static member inline enableRowGroup(v: bool) = - columnDefProp<'row, 'value> ("enableRowGroup" ==> v) - - static member inline enableCellChangeFlash(v: bool) = - columnDefProp<'row, 'value> ("enableCellChangeFlash" ==> v) - - static member inline field(v: string) = - columnDefProp<'row, 'value> ("field" ==> v) - - /// Usage: `ColumnDef.field _.FieldName` or `ColumnDef.field (fun x -> x.FieldName)` - static member inline field(f: 'row -> _) = - let idxOfFirstDot = (string f).IndexOf('.') - // `ColumnDef.field _.FirstName` and `ColumnDef.field (fun x -> x.FirstName)` both result in "FirstName". - let field = (string f).Substring(idxOfFirstDot + 1) - columnDefProp<'row, 'value> ("field" ==> field) - - static member inline filter(v: RowFilter) = - columnDefProp<'row, 'value> ("filter" ==> v.FilterText) - - static member inline filter(v: bool) = - columnDefProp<'row, 'value> ("filter" ==> v) - - static member inline floatingFilter(v: bool) = - columnDefProp<'row, 'value> ("floatingFilter" ==> v) - - static member inline headerCheckboxSelection(v: bool) = - columnDefProp<'row, 'value> ("headerCheckboxSelection" ==> v) - - static member inline headerClass(v: string) = - columnDefProp<'row, 'value> ("headerClass" ==> v) - - static member inline headerComponentFramework(callback: 'colId -> 'props -> ReactElement) = - columnDefProp<'row, 'value> ("headerComponentFramework" ==> fun p -> callback p?column?colId p) - - static member inline headerName(v: string) = - columnDefProp<'row, 'value> ("headerName" ==> v) - - static member inline wrapHeaderText(v: bool) = - columnDefProp<'row, 'value> ("wrapHeaderText" ==> v) - - static member inline autoHeaderHeight(v: bool) = - columnDefProp<'row, 'value> ("autoHeight" ==> v) - - static member inline hide(v: bool) = - columnDefProp<'row, 'value> ("hide" ==> v) - - static member inline maxWidth(v: int) = - columnDefProp<'row, 'value> ("maxWidth" ==> v) - - static member inline minWidth(v: int) = - columnDefProp<'row, 'value> ("minWidth" ==> v) - - static member inline onCellClicked(handler: 'value -> 'row -> unit) = - columnDefProp<'row, 'value> ("onCellClicked" ==> (fun p -> handler p?value p?data)) - - static member inline pinned(v: bool) = - columnDefProp<'row, 'value> ("pinned" ==> v) - - static member inline pivot(v: bool) = - columnDefProp<'row, 'value> ("pivot" ==> v) - - static member inline resizable(v: bool) = - columnDefProp<'row, 'value> ("resizable" ==> v) - - static member inline rowDrag(v: bool) = - columnDefProp<'row, 'value> ("rowDrag" ==> v) - - static member inline rowGroup(v: bool) = - columnDefProp<'row, 'value> ("rowGroup" ==> v) - - static member inline sortable(v: bool) = - columnDefProp<'row, 'value> ("sortable" ==> v) - - static member inline suppressKeyboardEvent callback = - columnDefProp<'row, 'value> ("suppressKeyboardEvent" ==> fun x -> callback x?event) - - static member inline suppressMovable = - columnDefProp<'row, 'value> ("suppressMovable" ==> true) - - static member inline valueFormatter(callback: IValueParams<'row, 'value> -> string) = - columnDefProp<'row, 'value> ("valueFormatter" ==> callback) - - static member inline valueGetter(f: 'row -> _) = - columnDefProp<'row, 'value> ("valueGetter" ==> (fun x -> f x?data)) - - static member inline valueSetter(f: IValueChangedParams<'row, 'value> -> unit) = - columnDefProp<'row, 'value> ("valueSetter" ==> f) - - static member inline valueSetter(f: IValueChangedParams<'row, 'value> -> bool) = - columnDefProp<'row, 'value> ("valueSetter" ==> f) - - static member inline valueParser(f: IValueChangedParams<'row, 'value> -> obj) = - columnDefProp<'row, 'value> ("valueParser" ==> f) // Is never called by AgGrid - - static member inline width(v: int) = - columnDefProp<'row, 'value> ("width" ==> v) - -[] -type IColumnGroupDefProp<'row> = interface end - -let columnGroupDefProp<'row> = unbox> - -[] -type ColumnGroup<'row> = - static member inline headerName(v: string) = - columnGroupDefProp<'row> ("headerName" ==> v) - - static member inline marryChildren(v: bool) = - columnGroupDefProp<'row> ("marryChildren" ==> v) - - static member inline openByDefault(v: bool) = - columnGroupDefProp<'row> ("openByDefault" ==> v) - - static member inline create (props: seq>) (children: seq>) = - let combinedProps = seq { - yield! props - columnGroupDefProp<'row> ("children" ==> Seq.toArray children) - } - - createObj !!combinedProps |> columnDef<'row> - -[] -type IAgGridProp<'row> = interface end - -let agGridProp<'row> (x: obj) = unbox> x - -[] -type AgGrid<'row> = - static member inline animateRows(v: bool) = agGridProp<'row> ("animateRows" ==> v) - - static member inline alwaysShowVerticalScroll(v: bool) = - agGridProp<'row> ("alwaysShowVerticalScroll" ==> v) - - static member inline columnDefs(columns: IColumnDef<'row> seq) = - agGridProp<'row> ("columnDefs", Seq.toArray !!columns) - - static member inline copyHeadersToClipboard(v: bool) = - agGridProp<'row> ("copyHeadersToClipboard" ==> v) - - static member inline domLayout(l: DOMLayout) = - agGridProp<'row> ("domLayout", l.LayoutText) - - static member inline enableCellTextSelection(v: bool) = - agGridProp<'row> ("enableCellTextSelection" ==> v) - - static member inline ensureDomOrder(v: bool) = - agGridProp<'row> ("ensureDomOrder" ==> v) - - static member inline enterNavigatesVertically(v: bool) = - agGridProp<'row> ("enterNavigatesVertically" ==> v) - - static member inline getRowNodeId(callback: 'row -> _) = - agGridProp<'row> ("getRowNodeId", callback) - - static member inline getRowId(callback: IGetRowIdParams<'row> -> string) = agGridProp<'row> ("getRowId", callback) - - static member inline onCellEditRequest(callback: obj -> unit) = - agGridProp<'row> ("onCellEditRequest", callback) - - static member inline onCellValueChanged callback = - agGridProp<'row> ("onCellValueChanged", (fun x -> callback x?data)) - - static member inline onPasteStart(callback: IPasteEvent<'row> -> unit) = - agGridProp<'row> ("onPasteStart", callback) - - static member inline onPasteEnd(callback: IPasteEvent<'row> -> unit) = - agGridProp<'row> ("onPasteEnd", callback) - - static member inline onRowClicked(handler: 'value -> 'row -> unit) = - agGridProp<'row> ("onRowClicked" ==> (fun p -> handler p?value p?data)) - - static member inline onSelectionChanged(callback: 'row array -> unit) = - agGridProp<'row> ("onSelectionChanged", (fun x -> x?api?getSelectedRows () |> callback)) - - static member inline readOnlyEdit(v: bool) = agGridProp<'row> ("readOnlyEdit" ==> v) - - static member inline singleClickEdit(v: bool) = - agGridProp<'row> ("singleClickEdit" ==> v) - - static member inline rowDeselection(v: bool) = agGridProp<'row> ("rowDeselection", v) - - static member inline rowSelection(s: RowSelection) = - agGridProp<'row> ("rowSelection", s.ToString().ToLower()) - - static member inline isRowSelectable(callback: 'row -> bool) = - agGridProp<'row> ("isRowSelectable" ==> fun x -> x?data |> callback) - - static member inline suppressRowClickSelection(v: bool) = - agGridProp<'row> ("suppressRowClickSelection" ==> v) - - static member inline rowHeight(h: int) = agGridProp<'row> ("rowHeight", h) - static member inline immutableData(v: bool) = agGridProp<'row> ("immutableData", v) - - /// Converts your data to a JS array to populate the grid. (This is less efficient than passing an array.) - static member inline rowData(data: 'row seq) = - agGridProp<'row> ("rowData", Seq.toArray data) - - static member inline rowData(data: 'row array) = agGridProp<'row> ("rowData", data) - - static member inline rowDragManaged(v: bool) = - agGridProp<'row> ("rowDragManaged" ==> v) - - static member inline defaultColDef(defaults: IColumnDefProp<'row, 'value> seq) = - agGridProp<'row> ("defaultColDef", defaults |> unbox<_ seq> |> createObj) - - static member onColumnGroupOpened(callback: _ -> unit) = // This can't be inline otherwise Fable produces invalid JS - let onColumnGroupOpened = - fun ev -> - {| - AutoSizeGroupColumns = - fun () -> - // Runs the column autoSize in a 0ms timeout so that the cellRenderer cells render before - // the grid calculates how large each cell is - JS.setTimeout - (fun () -> - let colIds = - ev?columnGroups - |> Seq.head - |> fun cg -> cg?children - |> Array.map (fun x -> x?colId) - - ev?api?autoSizeColumns colIds) - 0 - |> ignore - |} - |> callback - - agGridProp<'row> ("onColumnGroupOpened", onColumnGroupOpened) - - static member inline paginationPageSize(pageSize: int) = - agGridProp<'row> ("paginationPageSize", pageSize) - - static member inline paginationAutoPageSize(v: bool) = - agGridProp<'row> ("paginationAutoPageSize", v) - - static member inline pagination(v: bool) = agGridProp<'row> ("pagination", v) - - static member onGridReady(callback: _ -> unit) = // This can't be inline otherwise Fable produces invalid JS - let onGridReady = - fun ev -> - {| - AutoSizeAllColumns = - fun () -> - // Runs the column autoSize in a 0ms timeout so that the cellRendererFramework cells render - // before the grid calculates how large each cell is - JS.setTimeout - (fun () -> - let colIds = ev?api?getColumns () |> Array.map (fun x -> x?colId) - ev?api?autoSizeColumns colIds) - 0 - |> ignore - Export = fun () -> ev?api?exportDataAsCsv (obj ()) - |} - |> callback - - agGridProp<'row> ("onGridReady", onGridReady) - - static member inline processDataFromClipboard(callback: IProcessDataFromClipboardParams<'row> -> string[][]) = - agGridProp<'row> ("processDataFromClipboard", callback) - - static member inline enableRangeHandle(v: bool) = - agGridProp<'row> ("enableRangeHandle", v) - - static member inline enableRangeSelection(v: bool) = - agGridProp<'row> ("enableRangeSelection", v) - - static member inline pivotMode(v: bool) = agGridProp<'row> ("pivotMode", v) - static member inline treeData(v: bool) = agGridProp<'row> ("treeData", v) - - static member inline suppressAggFuncInHeader(v: bool) = - agGridProp<'row> ("suppressAggFuncInHeader", v) - - static member inline getContextMenuItems(callback: int -> int -> MenuItem list) = - agGridProp<'row> ( - "getContextMenuItems", - fun x -> - let menuItems = callback x?node?rowIndex x?column?colId - - [| - for item in menuItems do - match item with - | BuiltIn builtInItemName -> box builtInItemName - | Custom customMenuItem -> box customMenuItem - |] - ) - - static member inline headerHeight height = - agGridProp<'row> ("headerHeight", height) - - static member inline groupHeaderHeight height = - agGridProp<'row> ("groupHeaderHeight", height) - - [] - static member inline onCellFocused callback = - agGridProp<'row> ("onCellFocused", (fun x -> callback (int x?rowIndex) (int x?column?colId))) - - static member inline onCellFocused callback = - agGridProp<'row> ("onCellFocused", (fun (e: ICellFocusedEvent<'row>) -> callback e)) - - static member inline onRangeSelectionChanged callback = - agGridProp<'row> ( - "onRangeSelectionChanged", - fun x -> - let selectedRange = x?api?getCellRanges ()?at 0 - let startRow = selectedRange?startRow?rowIndex - let startColumn = selectedRange?columns?at 0?colId - let endRow = selectedRange?endRow?rowIndex - let endColumn = selectedRange?columns?at (selectedRange?columns?length - 1)?colId - - callback startRow startColumn endRow endColumn - ) - - static member inline popupParent parent = - agGridProp<'row> ("popupParent", parent) - - static member inline processDataFromClipboard(callback: string[][] -> string[][]) = - agGridProp<'row> ("processDataFromClipboard", (fun x -> callback x?data)) - - static member inline stopEditingWhenCellsLoseFocus(v: bool) = - agGridProp<'row> ("stopEditingWhenCellsLoseFocus", v) - - static member inline stopEditingWhenGridLosesFocus(v: bool) = - agGridProp<'row> ("stopEditingWhenGridLosesFocus", v) - - static member inline suppressClipboardApi(v: bool) = - agGridProp<'row> ("suppressClipboardApi", v) - - static member inline suppressCopyRowsToClipboard(v: bool) = - agGridProp<'row> ("suppressCopyRowsToClipboard", v) - - static member inline suppressCopySingleCellRanges(v: bool) = - agGridProp<'row> ("suppressCopySingleCellRanges", v) - - static member inline suppressMultiRangeSelection(v: bool) = - agGridProp<'row> ("suppressMultiRangeSelection", v) - - static member inline suppressRowHoverHighlight(v: bool) = - agGridProp<'row> ("suppressRowHoverHighlight", v) - - static member inline suppressScrollOnNewData(v: bool) = - agGridProp<'row> ("suppressScrollOnNewData", v) - - static member inline key(v: string) = agGridProp<'row> (prop.key v) - static member inline key(v: int) = agGridProp<'row> (prop.key v) - static member inline key(v: Guid) = agGridProp<'row> (prop.key v) - - static member inline dataTypeDefinitions(v: obj) = - agGridProp<'row> ("dataTypeDefinitions", v) - - static member inline enableFillHandle(v: bool) = - agGridProp<'row> ("enableFillHandle", v) - - static member inline rowGroupPanelShow(v: RowGroupPanelShow) = - agGridProp<'row> ("rowGroupPanelShow", v.RowGroupPanelShowText) - - static member inline groupDisplayType(v: RowGroupingDisplayType) = - agGridProp<'row> ("groupDisplayType", v.RowGroupingDisplayTypeText) - - static member inline undoRedoCellEditing(v: bool) = - agGridProp<'row> ("undoRedoCellEditing", v) - - static member inline undoRedoCellEditingLimit(v: int) = - agGridProp<'row> ("undoRedoCellEditingLimit", v) - - static member inline grid(props: IAgGridProp<'row> seq) = - Interop.reactApi.createElement (agGrid, createObj !!props) +module Feliz.AgGrid + +open System + +open Fable.Core +open Fable.Core.JsInterop +open Feliz + +// Suppress unused value warnings - they are often necessary for Fable bindings. +#nowarn "1182" + +let agGrid: obj = import "AgGridReact" "ag-grid-react" + +[] +[] +type LicenseManager = + static member setLicenseKey(key: string) : unit = jsNative + +/// See https://www.ag-grid.com/react-data-grid/row-object/. +[] +type IRowNode<'row> = { + id: string + data: 'row + updateData: 'row -> unit + setData: 'row -> unit + setSelected: bool -> unit + rowIndex: int + rowTop: int + displayed: bool + isHovered: bool + isFullWidthCell: bool + isSelected: bool +} + +[] +type ICellRange = { + id: string + startRow: obj + endRow: obj +} with + + member this.startRowIndex: int = this.startRow?rowIndex + member this.endRowIndex: int = this.endRow?rowIndex + +/// See https://www.ag-grid.com/react-data-grid/grid-interface/#grid-api. +[] +type IGridApi<'row> = + abstract copyToClipboard: unit -> unit + abstract pasteFromClipboard: unit -> unit + abstract refreshCells: unit -> unit + abstract redrawRows: unit -> unit + abstract setGridOption: string -> obj -> unit + abstract getSelectedNodes: unit -> IRowNode<'row>[] + abstract getCellRanges: unit -> ICellRange[] + +/// See https://www.ag-grid.com/react-data-grid/column-object/. +[] +type IColumn = { getColId: unit -> string } + +[] +type IColumnDefProp<'row, 'value> = interface end + +let columnDefProp<'row, 'value> = unbox> + +// Although the AG Grid docs suggest that this should have two type params, we only give it one so that column defs +// with different underlying value types can be used in the same list (for example in AgGrid.columnDefs). +[] +type IColumnDef<'row> = interface end + +let columnDef<'row> = unbox> + +[] +module CallbackParams = + /// See https://www.ag-grid.com/react-data-grid/column-properties/#reference-editing-valueSetter. + /// See https://www.ag-grid.com/react-data-grid/column-properties/#reference-editing-valueParser. + [] + type IValueChangedParams<'row, 'value> = { + oldValue: 'value + newValue: 'value + node: IRowNode<'row> + data: 'row + column: IColumn + colDef: IColumnDef<'row> + api: IGridApi<'row> + } with + + member this.rowIndex = this.node.rowIndex + + /// See https://www.ag-grid.com/react-data-grid/cell-editors/#custom-components. + [] + type IValueParams<'row, 'value> = { + value: 'value + data: 'row + node: IRowNode<'row> + colDef: IColumnDef<'row> + column: IColumn + api: IGridApi<'row> + rowIndex: int + } + + /// See https://www.ag-grid.com/react-data-grid/grid-events/#reference-selection-cellFocused. + [] + type ICellFocusedEvent<'row> = { + api: IGridApi<'row> + rowIndex: int + column: IColumn + isFullWidthCell: bool + } + + /// See https://www.ag-grid.com/react-data-grid//grid-options/#reference-rowModels-getRowId. + [] + type IGetRowIdParams<'row> = { + data: 'row + level: int + parentKeys: string[] + api: IGridApi<'row> + context: obj + } + + [] + type ICellRendererParams<'row, 'value> = { + value: 'value + data: 'row + node: IRowNode<'row> + colDef: IColumnDef<'row> + column: IColumn + api: IGridApi<'row> + rowIndex: int + } + + [] + type IPasteEvent<'row> = { + source: string + api: IGridApi<'row> + context: obj + ``type``: string + } + + [] + type IProcessDataFromClipboardParams<'row> = { + data: string[][] + api: IGridApi<'row> + context: obj + } + +type RowSelection = + | Single + | Multiple + +[] +type RowGroupingDisplayType = + | SingleColumn + | MultipleColumns + | GroupRows + | Custom + + member this.RowGroupingDisplayTypeText = + match this with + | SingleColumn -> "singleColumn" + | MultipleColumns -> "multipleColumns" + | GroupRows -> "groupRows" + | Custom -> "custom" + +[] +type RowGroupPanelShow = + | Always + | OnlyWhenGrouping + | Never + + member this.RowGroupPanelShowText = + match this with + | Always -> "always" + | OnlyWhenGrouping -> "onlyWhenGrouping" + | Never -> "never" + +[] +type RowFilter = + | Number + | Text + | Date + | Set + + member this.FilterText = sprintf "ag%OColumnFilter" this + +[] +type CellDataType = + | Text + | Number + | Date + | DateString + | Boolean + | Object + | Custom of string + + member this.CellDataTypeText = + match this with + | Text -> "text" + | Number -> "number" + | Date -> "date" + | DateString -> "dateString" + | Boolean -> "boolean" + | Object -> "object" + | Custom s -> s + +[] +type AgCellEditor = + | SelectCellEditor + | RichSelectCellEditor + | NumberCellEditor + | DateCellEditor + | DateStringCellEditor + | CheckboxCellEditor + | LargeTextCellEditor + | TextCellEditor + + member this.RichCellEditorText = sprintf "ag%O" this + +[] + +type AggregateFunction = + | Sum + | Min + | Max + | Count + | Avg + | First + | Last + + member this.AggregateText = (sprintf "%O" this).ToLower() + +type DOMLayout = + | Normal + | AutoHeight + | Print + + member this.LayoutText = + match this with + | Normal -> "normal" + | AutoHeight -> "autoHeight" + | Print -> "print" + +module ThemeClass = + let Alpine = "ag-theme-alpine" + let AlpineDark = "ag-theme-alpine-dark" + let Balham = "ag-theme-balham" + let BalhamDark = "ag-theme-balham-dark" + let Material = "ag-theme-material" + +type MenuItemDef = { + name: string + action: unit -> unit + shortcut: string + icon: obj //HtmlElement +} + +type MenuItem = + | BuiltIn of string + | Custom of MenuItemDef + +type ColumnType = + | RightAligned + | NumericColumn + +let openClosed = + function + | true -> "open" + | false -> "closed" + +[] +let CellRendererComponent<'row, 'value> + (render: ICellRendererParams<'row, 'value> -> ReactElement, p: ICellRendererParams<'row, 'value>) + = + render p + +[] +type ColumnDef<'row> = + // Constrain all props for a given column to be for the same value. + static member inline create<'value>(props: IColumnDefProp<'row, 'value> seq) = createObj !!props |> columnDef<'row> + + static member inline aggFunc(v: AggregateFunction) = + columnDefProp<'row, 'value> ("aggFunc" ==> v.AggregateText) + + static member inline autoComparator() = + columnDefProp<'row, 'value> ("comparator" ==> compare) + + static member inline cellClass(setClass: 'value -> 'row -> #seq) = + columnDefProp<'row, 'value> ("cellClass" ==> fun p -> setClass p?value p?data |> Seq.toArray) + + static member inline cellClassRules(rules: (string * ('value -> 'row -> bool)) list) = + columnDefProp<'row, 'value> ( + "cellClassRules" + ==> (rules + |> List.map (fun (className, rule) -> className ==> fun p -> rule p?value p?data) + |> createObj) + ) + + static member cellDataType(v: bool) = + columnDefProp<'row, 'value> ("cellDataType" ==> v) + + static member cellDataType(v: CellDataType) = + columnDefProp<'row, 'value> ("cellDataType" ==> v.CellDataTypeText) + + [] + static member cellRendererFramework _ = + failwith "cellRendererFramework isn't supported in the latest version of AgGrid. Use cellRenderer instead" + + static member cellRenderer(render: ICellRendererParams<'row, 'value> -> ReactElement) = + columnDefProp<'row, 'value> ("cellRenderer" ==> fun p -> CellRendererComponent(render, p)) + + static member cellEditor(render: ICellRendererParams<'row, 'value> -> ReactElement) = + columnDefProp<'row, 'value> ("cellEditor" ==> fun p -> CellRendererComponent(render, p)) + + static member cellEditor(v: string) = + columnDefProp<'row, 'value> ("cellEditor" ==> v) + + static member cellEditor(v: AgCellEditor) = + columnDefProp<'row, 'value> ("cellEditor" ==> v.RichCellEditorText) + + static member cellEditorParams(v: string seq) = + columnDefProp<'row, 'value> ("cellEditorParams" ==> {| values = v |> Seq.toArray |}) + + static member cellEditorParams(v: obj) = + columnDefProp<'row, 'value> ("cellEditorParams" ==> v) + + static member cellEditorPopup(v: bool) = + columnDefProp<'row, 'value> ("cellEditorPopup" ==> v) + + static member inline cellStyle(setStyle: 'value -> 'row -> _) = + columnDefProp<'row, 'value> ("cellStyle" ==> fun p -> setStyle p?value p?data) + + static member inline checkboxSelection(v: bool) = + columnDefProp<'row, 'value> ("checkboxSelection" ==> v) + + static member inline colId(v: string) = + columnDefProp<'row, 'value> ("colId" ==> v) + + static member inline columnGroupShow(v: bool) = + columnDefProp<'row, 'value> ("columnGroupShow" ==> openClosed v) + + static member inline columnType ct = + columnDefProp<'row, 'value> ( + "type" + ==> match ct with + | RightAligned -> "rightAligned" + | NumericColumn -> "numericColumn" + ) + + static member inline comparator(callback: 'a -> 'a -> int) = + columnDefProp<'row, 'value> ("comparator" ==> fun a b -> callback a b) + + static member inline editable(callback: 'value -> 'row -> bool) = + columnDefProp<'row, 'value> ("editable" ==> fun p -> callback p?value p?data) + + static member inline editable(v: bool) = + columnDefProp<'row, 'value> ("editable" ==> v) + + static member inline equals(callback: 'value -> 'value -> bool) = + columnDefProp<'row, 'value> ("equals" ==> callback) + + static member inline enableRowGroup(v: bool) = + columnDefProp<'row, 'value> ("enableRowGroup" ==> v) + + static member inline enableCellChangeFlash(v: bool) = + columnDefProp<'row, 'value> ("enableCellChangeFlash" ==> v) + + static member inline field(v: string) = + columnDefProp<'row, 'value> ("field" ==> v) + + /// Usage: `ColumnDef.field _.FieldName` or `ColumnDef.field (fun x -> x.FieldName)` + static member inline field(f: 'row -> _) = + let idxOfFirstDot = (string f).IndexOf('.') + // `ColumnDef.field _.FirstName` and `ColumnDef.field (fun x -> x.FirstName)` both result in "FirstName". + let field = (string f).Substring(idxOfFirstDot + 1) + columnDefProp<'row, 'value> ("field" ==> field) + + static member inline filter(v: RowFilter) = + columnDefProp<'row, 'value> ("filter" ==> v.FilterText) + + static member inline filter(v: bool) = + columnDefProp<'row, 'value> ("filter" ==> v) + + static member inline floatingFilter(v: bool) = + columnDefProp<'row, 'value> ("floatingFilter" ==> v) + + static member inline headerCheckboxSelection(v: bool) = + columnDefProp<'row, 'value> ("headerCheckboxSelection" ==> v) + + static member inline headerClass(v: string) = + columnDefProp<'row, 'value> ("headerClass" ==> v) + + static member inline headerComponentFramework(callback: 'colId -> 'props -> ReactElement) = + columnDefProp<'row, 'value> ("headerComponentFramework" ==> fun p -> callback p?column?colId p) + + static member inline headerName(v: string) = + columnDefProp<'row, 'value> ("headerName" ==> v) + + static member inline wrapHeaderText(v: bool) = + columnDefProp<'row, 'value> ("wrapHeaderText" ==> v) + + static member inline autoHeaderHeight(v: bool) = + columnDefProp<'row, 'value> ("autoHeight" ==> v) + + static member inline hide(v: bool) = + columnDefProp<'row, 'value> ("hide" ==> v) + + static member inline maxWidth(v: int) = + columnDefProp<'row, 'value> ("maxWidth" ==> v) + + static member inline minWidth(v: int) = + columnDefProp<'row, 'value> ("minWidth" ==> v) + + static member inline onCellClicked(handler: 'value -> 'row -> unit) = + columnDefProp<'row, 'value> ("onCellClicked" ==> (fun p -> handler p?value p?data)) + + static member inline pinned(v: bool) = + columnDefProp<'row, 'value> ("pinned" ==> v) + + static member inline pivot(v: bool) = + columnDefProp<'row, 'value> ("pivot" ==> v) + + static member inline resizable(v: bool) = + columnDefProp<'row, 'value> ("resizable" ==> v) + + static member inline rowDrag(v: bool) = + columnDefProp<'row, 'value> ("rowDrag" ==> v) + + static member inline rowGroup(v: bool) = + columnDefProp<'row, 'value> ("rowGroup" ==> v) + + static member inline sortable(v: bool) = + columnDefProp<'row, 'value> ("sortable" ==> v) + + static member inline suppressKeyboardEvent callback = + columnDefProp<'row, 'value> ("suppressKeyboardEvent" ==> fun x -> callback x?event) + + static member inline suppressMovable() = + columnDefProp<'row, 'value> ("suppressMovable" ==> true) + + static member inline valueFormatter(callback: IValueParams<'row, 'value> -> string) = + columnDefProp<'row, 'value> ("valueFormatter" ==> callback) + + static member inline valueGetter(f: 'row -> 'value) = + columnDefProp<'row, 'value> ("valueGetter" ==> (fun x -> f x?data)) + + static member inline valueSetter(f: IValueChangedParams<'row, 'value> -> unit) = + columnDefProp<'row, 'value> ("valueSetter" ==> f) + + static member inline valueSetter(f: IValueChangedParams<'row, 'value> -> bool) = + columnDefProp<'row, 'value> ("valueSetter" ==> f) + + static member inline valueParser(f: IValueChangedParams<'row, 'value> -> obj) = + columnDefProp<'row, 'value> ("valueParser" ==> f) // Is never called by AgGrid + + static member inline width(v: int) = + columnDefProp<'row, 'value> ("width" ==> v) + +[] +type IColumnGroupDefProp<'row> = interface end + +let columnGroupDefProp<'row> = unbox> + +[] +type ColumnGroup<'row> = + static member inline headerName(v: string) = + columnGroupDefProp<'row> ("headerName" ==> v) + + static member inline marryChildren(v: bool) = + columnGroupDefProp<'row> ("marryChildren" ==> v) + + static member inline openByDefault(v: bool) = + columnGroupDefProp<'row> ("openByDefault" ==> v) + + static member inline create (props: seq>) (children: seq>) = + let combinedProps = seq { + yield! props + columnGroupDefProp<'row> ("children" ==> Seq.toArray children) + } + + createObj !!combinedProps |> columnDef<'row> + +[] +type IAgGridProp<'row> = interface end + +let agGridProp<'row> (x: obj) = unbox> x + +[] +type AgGrid<'row> = + static member inline animateRows(v: bool) = agGridProp<'row> ("animateRows" ==> v) + + static member inline alwaysShowVerticalScroll(v: bool) = + agGridProp<'row> ("alwaysShowVerticalScroll" ==> v) + + static member inline columnDefs(columns: IColumnDef<'row> seq) = + agGridProp<'row> ("columnDefs", Seq.toArray !!columns) + + static member inline copyHeadersToClipboard(v: bool) = + agGridProp<'row> ("copyHeadersToClipboard" ==> v) + + static member inline domLayout(l: DOMLayout) = + agGridProp<'row> ("domLayout", l.LayoutText) + + static member inline enableCellTextSelection(v: bool) = + agGridProp<'row> ("enableCellTextSelection" ==> v) + + static member inline ensureDomOrder(v: bool) = + agGridProp<'row> ("ensureDomOrder" ==> v) + + static member inline enterNavigatesVertically(v: bool) = + agGridProp<'row> ("enterNavigatesVertically" ==> v) + + static member inline getRowNodeId(callback: 'row -> _) = + agGridProp<'row> ("getRowNodeId", callback) + + static member inline getRowId(callback: IGetRowIdParams<'row> -> string) = agGridProp<'row> ("getRowId", callback) + + static member inline onCellEditRequest(callback: obj -> unit) = + agGridProp<'row> ("onCellEditRequest", callback) + + static member inline onCellValueChanged callback = + agGridProp<'row> ("onCellValueChanged", (fun x -> callback x?data)) + + static member inline onPasteStart(callback: IPasteEvent<'row> -> unit) = + agGridProp<'row> ("onPasteStart", callback) + + static member inline onPasteEnd(callback: IPasteEvent<'row> -> unit) = + agGridProp<'row> ("onPasteEnd", callback) + + static member inline onRowClicked(handler: 'value -> 'row -> unit) = + agGridProp<'row> ("onRowClicked" ==> (fun p -> handler p?value p?data)) + + static member inline onSelectionChanged(callback: 'row array -> unit) = + agGridProp<'row> ("onSelectionChanged", (fun x -> x?api?getSelectedRows () |> callback)) + + static member inline readOnlyEdit(v: bool) = agGridProp<'row> ("readOnlyEdit" ==> v) + + static member inline singleClickEdit(v: bool) = + agGridProp<'row> ("singleClickEdit" ==> v) + + static member inline rowDeselection(v: bool) = agGridProp<'row> ("rowDeselection", v) + + static member inline rowSelection(s: RowSelection) = + agGridProp<'row> ("rowSelection", s.ToString().ToLower()) + + static member inline isRowSelectable(callback: 'row -> bool) = + agGridProp<'row> ("isRowSelectable" ==> fun x -> x?data |> callback) + + static member inline suppressRowClickSelection(v: bool) = + agGridProp<'row> ("suppressRowClickSelection" ==> v) + + static member inline rowHeight(h: int) = agGridProp<'row> ("rowHeight", h) + static member inline immutableData(v: bool) = agGridProp<'row> ("immutableData", v) + + /// Converts your data to a JS array to populate the grid. (This is less efficient than passing an array.) + static member inline rowData(data: 'row seq) = + agGridProp<'row> ("rowData", Seq.toArray data) + + static member inline rowData(data: 'row array) = agGridProp<'row> ("rowData", data) + + static member inline rowDragManaged(v: bool) = + agGridProp<'row> ("rowDragManaged" ==> v) + + static member inline defaultColDef(defaults: IColumnDefProp<'row, 'value> seq) = + agGridProp<'row> ("defaultColDef", defaults |> unbox<_ seq> |> createObj) + + static member onColumnGroupOpened(callback: _ -> unit) = // This can't be inline otherwise Fable produces invalid JS + let onColumnGroupOpened = + fun ev -> + {| + AutoSizeGroupColumns = + fun () -> + // Runs the column autoSize in a 0ms timeout so that the cellRenderer cells render before + // the grid calculates how large each cell is + JS.setTimeout + (fun () -> + let colIds = + ev?columnGroups + |> Seq.head + |> fun cg -> cg?children + |> Array.map (fun x -> x?colId) + + ev?api?autoSizeColumns colIds) + 0 + |> ignore + |} + |> callback + + agGridProp<'row> ("onColumnGroupOpened", onColumnGroupOpened) + + static member inline paginationPageSize(pageSize: int) = + agGridProp<'row> ("paginationPageSize", pageSize) + + static member inline paginationAutoPageSize(v: bool) = + agGridProp<'row> ("paginationAutoPageSize", v) + + static member inline pagination(v: bool) = agGridProp<'row> ("pagination", v) + + static member onGridReady(callback: _ -> unit) = // This can't be inline otherwise Fable produces invalid JS + let onGridReady = + fun ev -> + {| + AutoSizeAllColumns = + fun () -> + // Runs the column autoSize in a 0ms timeout so that the cellRendererFramework cells render + // before the grid calculates how large each cell is + JS.setTimeout + (fun () -> + let colIds = ev?api?getColumns () |> Array.map (fun x -> x?colId) + ev?api?autoSizeColumns colIds) + 0 + |> ignore + Export = fun () -> ev?api?exportDataAsCsv (obj ()) + |} + |> callback + + agGridProp<'row> ("onGridReady", onGridReady) + + static member inline processDataFromClipboard(callback: IProcessDataFromClipboardParams<'row> -> string[][]) = + agGridProp<'row> ("processDataFromClipboard", callback) + + static member inline enableRangeHandle(v: bool) = + agGridProp<'row> ("enableRangeHandle", v) + + static member inline enableRangeSelection(v: bool) = + agGridProp<'row> ("enableRangeSelection", v) + + static member inline pivotMode(v: bool) = agGridProp<'row> ("pivotMode", v) + static member inline treeData(v: bool) = agGridProp<'row> ("treeData", v) + + static member inline suppressAggFuncInHeader(v: bool) = + agGridProp<'row> ("suppressAggFuncInHeader", v) + + static member inline getContextMenuItems(callback: int -> int -> MenuItem list) = + agGridProp<'row> ( + "getContextMenuItems", + fun x -> + let menuItems = callback x?node?rowIndex x?column?colId + + [| + for item in menuItems do + match item with + | BuiltIn builtInItemName -> box builtInItemName + | Custom customMenuItem -> box customMenuItem + |] + ) + + static member inline headerHeight height = + agGridProp<'row> ("headerHeight", height) + + static member inline groupHeaderHeight height = + agGridProp<'row> ("groupHeaderHeight", height) + + [] + static member inline onCellFocused callback = + agGridProp<'row> ("onCellFocused", (fun x -> callback (int x?rowIndex) (int x?column?colId))) + + static member inline onCellFocused callback = + agGridProp<'row> ("onCellFocused", (fun (e: ICellFocusedEvent<'row>) -> callback e)) + + static member inline onRangeSelectionChanged callback = + agGridProp<'row> ( + "onRangeSelectionChanged", + fun x -> + let selectedRange = x?api?getCellRanges ()?at 0 + let startRow = selectedRange?startRow?rowIndex + let startColumn = selectedRange?columns?at 0?colId + let endRow = selectedRange?endRow?rowIndex + let endColumn = selectedRange?columns?at (selectedRange?columns?length - 1)?colId + + callback startRow startColumn endRow endColumn + ) + + static member inline popupParent parent = + agGridProp<'row> ("popupParent", parent) + + static member inline processDataFromClipboard(callback: string[][] -> string[][]) = + agGridProp<'row> ("processDataFromClipboard", (fun x -> callback x?data)) + + static member inline stopEditingWhenCellsLoseFocus(v: bool) = + agGridProp<'row> ("stopEditingWhenCellsLoseFocus", v) + + static member inline stopEditingWhenGridLosesFocus(v: bool) = + agGridProp<'row> ("stopEditingWhenGridLosesFocus", v) + + static member inline suppressClipboardApi(v: bool) = + agGridProp<'row> ("suppressClipboardApi", v) + + static member inline suppressCopyRowsToClipboard(v: bool) = + agGridProp<'row> ("suppressCopyRowsToClipboard", v) + + static member inline suppressCopySingleCellRanges(v: bool) = + agGridProp<'row> ("suppressCopySingleCellRanges", v) + + static member inline suppressMultiRangeSelection(v: bool) = + agGridProp<'row> ("suppressMultiRangeSelection", v) + + static member inline suppressRowHoverHighlight(v: bool) = + agGridProp<'row> ("suppressRowHoverHighlight", v) + + static member inline suppressScrollOnNewData(v: bool) = + agGridProp<'row> ("suppressScrollOnNewData", v) + + static member inline key(v: string) = agGridProp<'row> (prop.key v) + static member inline key(v: int) = agGridProp<'row> (prop.key v) + static member inline key(v: Guid) = agGridProp<'row> (prop.key v) + + static member inline dataTypeDefinitions(v: obj) = + agGridProp<'row> ("dataTypeDefinitions", v) + + static member inline enableFillHandle(v: bool) = + agGridProp<'row> ("enableFillHandle", v) + + static member inline rowGroupPanelShow(v: RowGroupPanelShow) = + agGridProp<'row> ("rowGroupPanelShow", v.RowGroupPanelShowText) + + static member inline groupDisplayType(v: RowGroupingDisplayType) = + agGridProp<'row> ("groupDisplayType", v.RowGroupingDisplayTypeText) + + static member inline undoRedoCellEditing(v: bool) = + agGridProp<'row> ("undoRedoCellEditing", v) + + static member inline undoRedoCellEditingLimit(v: int) = + agGridProp<'row> ("undoRedoCellEditingLimit", v) + + static member inline grid(props: IAgGridProp<'row> seq) = + Interop.reactApi.createElement (agGrid, createObj !!props) From 7b9ee80f4eb33a72a5afe8c2432c2419a8c90262 Mon Sep 17 00:00:00 2001 From: Jaz Thomson Date: Fri, 19 Jul 2024 16:00:26 +0100 Subject: [PATCH 15/27] Split enterprise features into their own module --- src/AgGrid.fs | 200 ++++++++++++++++++++++++++++++-------------------- 1 file changed, 119 insertions(+), 81 deletions(-) diff --git a/src/AgGrid.fs b/src/AgGrid.fs index d10a565..8091047 100644 --- a/src/AgGrid.fs +++ b/src/AgGrid.fs @@ -45,8 +45,6 @@ type ICellRange = { /// See https://www.ag-grid.com/react-data-grid/grid-interface/#grid-api. [] type IGridApi<'row> = - abstract copyToClipboard: unit -> unit - abstract pasteFromClipboard: unit -> unit abstract refreshCells: unit -> unit abstract redrawRows: unit -> unit abstract setGridOption: string -> obj -> unit @@ -147,38 +145,13 @@ type RowSelection = | Single | Multiple -[] -type RowGroupingDisplayType = - | SingleColumn - | MultipleColumns - | GroupRows - | Custom - - member this.RowGroupingDisplayTypeText = - match this with - | SingleColumn -> "singleColumn" - | MultipleColumns -> "multipleColumns" - | GroupRows -> "groupRows" - | Custom -> "custom" -[] -type RowGroupPanelShow = - | Always - | OnlyWhenGrouping - | Never - - member this.RowGroupPanelShowText = - match this with - | Always -> "always" - | OnlyWhenGrouping -> "onlyWhenGrouping" - | Never -> "never" [] type RowFilter = | Number | Text | Date - | Set member this.FilterText = sprintf "ag%OColumnFilter" this @@ -205,7 +178,6 @@ type CellDataType = [] type AgCellEditor = | SelectCellEditor - | RichSelectCellEditor | NumberCellEditor | DateCellEditor | DateStringCellEditor @@ -213,20 +185,7 @@ type AgCellEditor = | LargeTextCellEditor | TextCellEditor - member this.RichCellEditorText = sprintf "ag%O" this - -[] - -type AggregateFunction = - | Sum - | Min - | Max - | Count - | Avg - | First - | Last - - member this.AggregateText = (sprintf "%O" this).ToLower() + member this.CellEditorText = sprintf "ag%O" this type DOMLayout = | Normal @@ -246,17 +205,6 @@ module ThemeClass = let BalhamDark = "ag-theme-balham-dark" let Material = "ag-theme-material" -type MenuItemDef = { - name: string - action: unit -> unit - shortcut: string - icon: obj //HtmlElement -} - -type MenuItem = - | BuiltIn of string - | Custom of MenuItemDef - type ColumnType = | RightAligned | NumericColumn @@ -277,9 +225,6 @@ type ColumnDef<'row> = // Constrain all props for a given column to be for the same value. static member inline create<'value>(props: IColumnDefProp<'row, 'value> seq) = createObj !!props |> columnDef<'row> - static member inline aggFunc(v: AggregateFunction) = - columnDefProp<'row, 'value> ("aggFunc" ==> v.AggregateText) - static member inline autoComparator() = columnDefProp<'row, 'value> ("comparator" ==> compare) @@ -314,7 +259,7 @@ type ColumnDef<'row> = columnDefProp<'row, 'value> ("cellEditor" ==> v) static member cellEditor(v: AgCellEditor) = - columnDefProp<'row, 'value> ("cellEditor" ==> v.RichCellEditorText) + columnDefProp<'row, 'value> ("cellEditor" ==> v.CellEditorText) static member cellEditorParams(v: string seq) = columnDefProp<'row, 'value> ("cellEditorParams" ==> {| values = v |> Seq.toArray |}) @@ -415,8 +360,7 @@ type ColumnDef<'row> = static member inline pinned(v: bool) = columnDefProp<'row, 'value> ("pinned" ==> v) - static member inline pivot(v: bool) = - columnDefProp<'row, 'value> ("pivot" ==> v) + static member inline resizable(v: bool) = columnDefProp<'row, 'value> ("resizable" ==> v) @@ -623,26 +567,10 @@ type AgGrid<'row> = static member inline enableRangeSelection(v: bool) = agGridProp<'row> ("enableRangeSelection", v) - static member inline pivotMode(v: bool) = agGridProp<'row> ("pivotMode", v) - static member inline treeData(v: bool) = agGridProp<'row> ("treeData", v) static member inline suppressAggFuncInHeader(v: bool) = agGridProp<'row> ("suppressAggFuncInHeader", v) - static member inline getContextMenuItems(callback: int -> int -> MenuItem list) = - agGridProp<'row> ( - "getContextMenuItems", - fun x -> - let menuItems = callback x?node?rowIndex x?column?colId - - [| - for item in menuItems do - match item with - | BuiltIn builtInItemName -> box builtInItemName - | Custom customMenuItem -> box customMenuItem - |] - ) - static member inline headerHeight height = agGridProp<'row> ("headerHeight", height) @@ -709,12 +637,6 @@ type AgGrid<'row> = static member inline enableFillHandle(v: bool) = agGridProp<'row> ("enableFillHandle", v) - static member inline rowGroupPanelShow(v: RowGroupPanelShow) = - agGridProp<'row> ("rowGroupPanelShow", v.RowGroupPanelShowText) - - static member inline groupDisplayType(v: RowGroupingDisplayType) = - agGridProp<'row> ("groupDisplayType", v.RowGroupingDisplayTypeText) - static member inline undoRedoCellEditing(v: bool) = agGridProp<'row> ("undoRedoCellEditing", v) @@ -723,3 +645,119 @@ type AgGrid<'row> = static member inline grid(props: IAgGridProp<'row> seq) = Interop.reactApi.createElement (agGrid, createObj !!props) + + module Enterprise = + + [] + type RowFilter = + | Number + | Text + | Date + | Set + | MultiColumn + + member this.FilterText = sprintf "ag%OColumnFilter" this + + [] + type AgCellEditor = + | SelectCellEditor + | NumberCellEditor + | DateCellEditor + | DateStringCellEditor + | CheckboxCellEditor + | LargeTextCellEditor + | TextCellEditor + | RichSelectCellEditor + + member this.RichCellEditorText = sprintf "ag%O" this + + [] + type RowGroupingDisplayType = + | SingleColumn + | MultipleColumns + | GroupRows + | Custom + + member this.RowGroupingDisplayTypeText = + match this with + | SingleColumn -> "singleColumn" + | MultipleColumns -> "multipleColumns" + | GroupRows -> "groupRows" + | Custom -> "custom" + + [] + type RowGroupPanelShow = + | Always + | OnlyWhenGrouping + | Never + + member this.RowGroupPanelShowText = + match this with + | Always -> "always" + | OnlyWhenGrouping -> "onlyWhenGrouping" + | Never -> "never" + + [] + type AggregateFunction = + | Sum + | Min + | Max + | Count + | Avg + | First + | Last + + member this.AggregateText = (sprintf "%O" this).ToLower() + + type MenuItemDef = { + name: string + action: unit -> unit + shortcut: string + icon: obj //HtmlElement + } + + type MenuItem = + | BuiltIn of string + | Custom of MenuItemDef + + /// See https://www.ag-grid.com/react-data-grid/grid-interface/#grid-api. + [] + type IGridApi<'row> = + abstract copyToClipboard: unit -> unit + abstract pasteFromClipboard: unit -> unit + abstract refreshCells: unit -> unit + abstract redrawRows: unit -> unit + abstract setGridOption: string -> obj -> unit + abstract getSelectedNodes: unit -> IRowNode<'row>[] + abstract getCellRanges: unit -> ICellRange[] + + [] + type ColumnDef<'row> = + static member inline filter(v: RowFilter) = columnDefProp<'row, 'value> ("filter" ==> v.FilterText) + static member cellEditor(v: AgCellEditor) = columnDefProp<'row, 'value> ("cellEditor" ==> v.RichCellEditorText) + static member inline pivot(v: bool) = columnDefProp<'row, 'value> ("pivot" ==> v) + + [] + type AgGrid<'row> = + static member inline rowGroupPanelShow(v: RowGroupPanelShow) = + agGridProp<'row> ("rowGroupPanelShow", v.RowGroupPanelShowText) + static member inline aggFunc(v: AggregateFunction) = columnDefProp<'row, 'value> ("aggFunc" ==> v.AggregateText) + + static member inline groupDisplayType(v: RowGroupingDisplayType) = + agGridProp<'row> ("groupDisplayType", v.RowGroupingDisplayTypeText) + + static member inline pivotMode(v: bool) = agGridProp<'row> ("pivotMode", v) + static member inline treeData(v: bool) = agGridProp<'row> ("treeData", v) + static member inline getContextMenuItems(callback: int -> int -> MenuItem list) = + agGridProp<'row> ( + "getContextMenuItems", + fun x -> + let menuItems = callback x?node?rowIndex x?column?colId + + [| + for item in menuItems do + match item with + | BuiltIn builtInItemName -> box builtInItemName + | Custom customMenuItem -> box customMenuItem + |] + ) From dc48b679ef5cc906d5f2ad9f4d165ff676fd375c Mon Sep 17 00:00:00 2001 From: Joost Kaptein Date: Fri, 16 Aug 2024 15:57:08 +0100 Subject: [PATCH 16/27] Fix MultiColumn not working due to naming error --- src/AgGrid.fs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/AgGrid.fs b/src/AgGrid.fs index 8091047..3be2e82 100644 --- a/src/AgGrid.fs +++ b/src/AgGrid.fs @@ -654,7 +654,7 @@ type AgGrid<'row> = | Text | Date | Set - | MultiColumn + | Multi member this.FilterText = sprintf "ag%OColumnFilter" this @@ -760,4 +760,4 @@ type AgGrid<'row> = | BuiltIn builtInItemName -> box builtInItemName | Custom customMenuItem -> box customMenuItem |] - ) + ) \ No newline at end of file From 3c711224b2572a077679dafa7d0e1ce62fc9030e Mon Sep 17 00:00:00 2001 From: Joost Kaptein Date: Fri, 16 Aug 2024 16:21:51 +0100 Subject: [PATCH 17/27] DU for built in menu items --- src/AgGrid.fs | 38 ++++++++++++++++++++++++++++++++++++-- 1 file changed, 36 insertions(+), 2 deletions(-) diff --git a/src/AgGrid.fs b/src/AgGrid.fs index 3be2e82..25c66d8 100644 --- a/src/AgGrid.fs +++ b/src/AgGrid.fs @@ -716,8 +716,42 @@ type AgGrid<'row> = icon: obj //HtmlElement } + [] + type BuiltInMenuItem = + | AutoSizeAll + | ExpandAll + | ContractAll + | Copy + | CopyWithHeaders + | CopyWithGroupHeaders + | Cut + | Paste + | ResetColumns + | Export + | CsvExport + | ExcelExport + | ChartRange + | PivotChart + + member this.BuiltInMenuItemText = + match this with + | AutoSizeAll -> "autoSizeAll" + | ExpandAll -> "expandAll" + | ContractAll -> "contractAll" + | Copy -> "copy" + | CopyWithHeaders -> "copyWithHeaders" + | CopyWithGroupHeaders -> "copyWithGroupHeaders" + | Cut -> "cut" + | Paste -> "paste" + | ResetColumns -> "resetColumns" + | Export -> "export" + | CsvExport -> "csvExport" + | ExcelExport -> "excelExport" + | ChartRange -> "chartRange" + | PivotChart -> "pivotChart" + type MenuItem = - | BuiltIn of string + | BuiltIn of BuiltInMenuItem | Custom of MenuItemDef /// See https://www.ag-grid.com/react-data-grid/grid-interface/#grid-api. @@ -757,7 +791,7 @@ type AgGrid<'row> = [| for item in menuItems do match item with - | BuiltIn builtInItemName -> box builtInItemName + | BuiltIn builtInItemName -> box builtInItemName.BuiltInMenuItemText | Custom customMenuItem -> box customMenuItem |] ) \ No newline at end of file From 8baaca8de2fe4411148ce887f8b2cf4bb30dfc8c Mon Sep 17 00:00:00 2001 From: Joost Kaptein Date: Fri, 30 Aug 2024 12:41:50 +0100 Subject: [PATCH 18/27] Cell renderer and value formatter should be able to deal with null data --- src/AgGrid.fs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/AgGrid.fs b/src/AgGrid.fs index 25c66d8..ebabb72 100644 --- a/src/AgGrid.fs +++ b/src/AgGrid.fs @@ -87,8 +87,8 @@ module CallbackParams = /// See https://www.ag-grid.com/react-data-grid/cell-editors/#custom-components. [] type IValueParams<'row, 'value> = { - value: 'value - data: 'row + value: 'value option + data: 'row option node: IRowNode<'row> colDef: IColumnDef<'row> column: IColumn @@ -117,8 +117,8 @@ module CallbackParams = [] type ICellRendererParams<'row, 'value> = { - value: 'value - data: 'row + value: 'value option + data: 'row option node: IRowNode<'row> colDef: IColumnDef<'row> column: IColumn From 6049cc26172c8389b499624b203b9545051fdb34 Mon Sep 17 00:00:00 2001 From: Joost Kaptein Date: Fri, 30 Aug 2024 12:45:49 +0100 Subject: [PATCH 19/27] Let ValueGetter play nicely with empty values that occur when using column grouping --- src/AgGrid.fs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/AgGrid.fs b/src/AgGrid.fs index ebabb72..457fcec 100644 --- a/src/AgGrid.fs +++ b/src/AgGrid.fs @@ -384,7 +384,7 @@ type ColumnDef<'row> = columnDefProp<'row, 'value> ("valueFormatter" ==> callback) static member inline valueGetter(f: 'row -> 'value) = - columnDefProp<'row, 'value> ("valueGetter" ==> (fun x -> f x?data)) + columnDefProp<'row, 'value> ("valueGetter" ==> (fun (x:{|data: 'row option|}) -> x.data |> Option.map f )) static member inline valueSetter(f: IValueChangedParams<'row, 'value> -> unit) = columnDefProp<'row, 'value> ("valueSetter" ==> f) From 338247f49146533ecbcf9f793e155b03826a884f Mon Sep 17 00:00:00 2001 From: Joost Kaptein Date: Fri, 30 Aug 2024 12:53:01 +0100 Subject: [PATCH 20/27] Move aggFunction to ColumnDef; add rowGroup ColumnDef --- src/AgGrid.fs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/AgGrid.fs b/src/AgGrid.fs index 457fcec..885e6d7 100644 --- a/src/AgGrid.fs +++ b/src/AgGrid.fs @@ -770,12 +770,13 @@ type AgGrid<'row> = static member inline filter(v: RowFilter) = columnDefProp<'row, 'value> ("filter" ==> v.FilterText) static member cellEditor(v: AgCellEditor) = columnDefProp<'row, 'value> ("cellEditor" ==> v.RichCellEditorText) static member inline pivot(v: bool) = columnDefProp<'row, 'value> ("pivot" ==> v) + static member inline aggFunc(v: AggregateFunction) = columnDefProp<'row, 'value> ("aggFunc" ==> v.AggregateText) + static member inline rowGroup(v: bool) = columnDefProp<'row, 'value> ("rowGroup" ==> v) [] type AgGrid<'row> = static member inline rowGroupPanelShow(v: RowGroupPanelShow) = agGridProp<'row> ("rowGroupPanelShow", v.RowGroupPanelShowText) - static member inline aggFunc(v: AggregateFunction) = columnDefProp<'row, 'value> ("aggFunc" ==> v.AggregateText) static member inline groupDisplayType(v: RowGroupingDisplayType) = agGridProp<'row> ("groupDisplayType", v.RowGroupingDisplayTypeText) From c89e2c9dcd49b695ac4d0a7bcacef0228c099085 Mon Sep 17 00:00:00 2001 From: Joost Kaptein Date: Fri, 30 Aug 2024 13:18:28 +0100 Subject: [PATCH 21/27] fix demo after introducing breaking changes --- demo/src/Components.fs | 20 +++++++++++++------- 1 file changed, 13 insertions(+), 7 deletions(-) diff --git a/demo/src/Components.fs b/demo/src/Components.fs index 2a9333a..d148c69 100644 --- a/demo/src/Components.fs +++ b/demo/src/Components.fs @@ -205,7 +205,7 @@ let Demo () = ColumnDef.headerName "Age" ColumnDef.valueGetter (fun x -> x.Age) ColumnDef.valueFormatter (fun valueParams -> - match valueParams.value with + match Option.flatten valueParams.value with | Some age -> $"%i{age} years" | None -> "Unknown") ] @@ -223,7 +223,9 @@ let Demo () = | [| d; m; y |] -> DateTime(int y, int m, int d) | _ -> DateTime.MinValue) ColumnDef.valueFormatter (fun valueParams -> - valueParams.value.ToShortDateString()) + valueParams.value + |> Option.map _.ToShortDateString() + |> Option.defaultValue "") ] ColumnDef.create [ ColumnDef.filter RowFilter.Text @@ -241,13 +243,17 @@ let Demo () = ColumnDef.columnType ColumnType.NumericColumn ColumnDef.valueGetter (fun x -> x.Total) ColumnDef.cellRenderer (fun rendererParams -> - Html.span [ + match rendererParams.value with + | Some value -> Html.span [ - prop.style [ style.fontSize 9 ] - prop.children [ Html.text "🏅" ] + Html.span [ + prop.style [ style.fontSize 9 ] + prop.children [ Html.text "🏅" ] + ] + Html.text $"%i{value}" ] - Html.text $"%i{rendererParams.value}" - ]) + | None -> React.fragment [] + ) ColumnDef.columnGroupShow true ] ColumnDef.create [ From 2b81c8cc6298f42639b4b8d551d9b9327b76f035 Mon Sep 17 00:00:00 2001 From: Joost Kaptein Date: Fri, 30 Aug 2024 14:15:57 +0100 Subject: [PATCH 22/27] add GetDataPath function to support treeData attribute --- src/AgGrid.fs | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/AgGrid.fs b/src/AgGrid.fs index 885e6d7..e8b136c 100644 --- a/src/AgGrid.fs +++ b/src/AgGrid.fs @@ -782,7 +782,10 @@ type AgGrid<'row> = agGridProp<'row> ("groupDisplayType", v.RowGroupingDisplayTypeText) static member inline pivotMode(v: bool) = agGridProp<'row> ("pivotMode", v) + + static member inline getDataPath( v: 'row -> string array) = agGridProp<'row> ("getDataPath", v) static member inline treeData(v: bool) = agGridProp<'row> ("treeData", v) + static member inline getContextMenuItems(callback: int -> int -> MenuItem list) = agGridProp<'row> ( "getContextMenuItems", @@ -795,4 +798,4 @@ type AgGrid<'row> = | BuiltIn builtInItemName -> box builtInItemName.BuiltInMenuItemText | Custom customMenuItem -> box customMenuItem |] - ) \ No newline at end of file + ) From 40801f8e66c41c91023146afa0ddff9f43abd25d Mon Sep 17 00:00:00 2001 From: Matt Gallagher Date: Fri, 6 Sep 2024 16:20:19 +0100 Subject: [PATCH 23/27] Use .NET 8 SDK --- global.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/global.json b/global.json index 1b8195c..c19a2e0 100644 --- a/global.json +++ b/global.json @@ -1,6 +1,6 @@ { "sdk": { - "version": "6.0.100", + "version": "8.0.100", "rollForward": "latestMinor" } } From 1f65f5254499b78c0883d3419382793932be004a Mon Sep 17 00:00:00 2001 From: Matt Gallagher Date: Fri, 6 Sep 2024 16:20:53 +0100 Subject: [PATCH 24/27] Handle .mjs files in webpack --- demo/webpack.config.js | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/demo/webpack.config.js b/demo/webpack.config.js index 6e81c83..772fe6c 100644 --- a/demo/webpack.config.js +++ b/demo/webpack.config.js @@ -117,6 +117,11 @@ module.exports = { // - file-loader: Moves files referenced in the code (fonts, images) into output folder module: { rules: [ + { + test: /\.mjs$/, + include: /node_modules/, + type: 'javascript/auto' + }, { test: /\.(js|jsx)$/, exclude: /node_modules/, From 9024a45620b2ed99f349083fe2943db282511650 Mon Sep 17 00:00:00 2001 From: Matt Gallagher Date: Fri, 6 Sep 2024 16:21:29 +0100 Subject: [PATCH 25/27] Fix .md indentation --- demo/README.md | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/demo/README.md b/demo/README.md index ae20e35..3c02b5f 100644 --- a/demo/README.md +++ b/demo/README.md @@ -8,13 +8,13 @@ ## Deploy - Change the reference to the src project into a reference to the appropriate NuGet package, e.g.: - ``` diff - - - - - - - - - - + - ``` + ```diff + + - + - + - + + + + + ``` - Run `npm run publish-docs` From f5ded7ad81f011cb6be71df5ba57c7bc8ddba264 Mon Sep 17 00:00:00 2001 From: Joost Kaptein Date: Fri, 4 Oct 2024 11:52:32 +0200 Subject: [PATCH 26/27] remove unused api version --- src/AgGrid.fs | 13 +------------ 1 file changed, 1 insertion(+), 12 deletions(-) diff --git a/src/AgGrid.fs b/src/AgGrid.fs index e8b136c..04a0c21 100644 --- a/src/AgGrid.fs +++ b/src/AgGrid.fs @@ -754,17 +754,6 @@ type AgGrid<'row> = | BuiltIn of BuiltInMenuItem | Custom of MenuItemDef - /// See https://www.ag-grid.com/react-data-grid/grid-interface/#grid-api. - [] - type IGridApi<'row> = - abstract copyToClipboard: unit -> unit - abstract pasteFromClipboard: unit -> unit - abstract refreshCells: unit -> unit - abstract redrawRows: unit -> unit - abstract setGridOption: string -> obj -> unit - abstract getSelectedNodes: unit -> IRowNode<'row>[] - abstract getCellRanges: unit -> ICellRange[] - [] type ColumnDef<'row> = static member inline filter(v: RowFilter) = columnDefProp<'row, 'value> ("filter" ==> v.FilterText) @@ -798,4 +787,4 @@ type AgGrid<'row> = | BuiltIn builtInItemName -> box builtInItemName.BuiltInMenuItemText | Custom customMenuItem -> box customMenuItem |] - ) + ) \ No newline at end of file From ae7d0a1bb811c34e30906ae1997238b8e96e970c Mon Sep 17 00:00:00 2001 From: Joost Kaptein Date: Fri, 4 Oct 2024 11:54:19 +0200 Subject: [PATCH 27/27] Use options in menuItemDef where possible --- src/AgGrid.fs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/AgGrid.fs b/src/AgGrid.fs index 04a0c21..eb2c120 100644 --- a/src/AgGrid.fs +++ b/src/AgGrid.fs @@ -711,9 +711,9 @@ type AgGrid<'row> = type MenuItemDef = { name: string - action: unit -> unit - shortcut: string - icon: obj //HtmlElement + action: (unit -> unit) option + shortcut: string option + icon: obj option//HtmlElement } [] @@ -787,4 +787,4 @@ type AgGrid<'row> = | BuiltIn builtInItemName -> box builtInItemName.BuiltInMenuItemText | Custom customMenuItem -> box customMenuItem |] - ) \ No newline at end of file + )