Hi,
this worked for me:
dagfuncs.DMC_Select = class {
// gets called once before the renderer is used
init(params) {
// store the params
this.params = params;
// function for when Dash is trying to send props back to the component / server
var setProps = (props) => {
if (typeof props.value != typeof undefined) {
// updates the value of the editor
this.value = props.value;
// re-enables keyboard event
delete params.colDef.suppressKeyboardEvent;
// tells the grid to stop editing the cell
params.api.stopEditing();
// sets focus back to the grid's previously active cell
this.prevFocus.focus();
}
};
// create an element for the editor
this.eInput = document.createElement('div');
// create the root for rendering the React component
this.root = ReactDOM.createRoot(this.eInput);
// Get MantineProvider and Select from window
const MantineProvider = window.dash_mantine_components.MantineProvider;
const Select = window.dash_mantine_components.Select;
// Get global theme, styles, and other settings if available
const globalMantineConfig = {
theme: window.dash_mantine_components.mantineTheme || {},
styles: window.dash_mantine_components.mantineStyles || {},
colorScheme: window.dash_mantine_components.mantineColorScheme || 'light',
emotionCache: window.dash_mantine_components.mantineEmotionCache || null,
withGlobalStyles: true,
withNormalizeCSS: true,
};
// Render the Select component wrapped in the MantineProvider
this.root.render(
React.createElement(
MantineProvider,
globalMantineConfig,
React.createElement(Select, {
data: params.options,
value: params.value,
setProps,
style: {
position: 'fixed',
width: params.column.actualWidth - 2,
...params.style,
},
className: params.className,
clearable: params.clearable,
searchable: params.searchable || true,
creatable: params.creatable,
debounce: params.debounce,
disabled: params.disabled,
filterDataOnExactSearchMatch: params.filterDataOnExactSearchMatch,
limit: params.limit,
maxDropdownHeight: params.maxDropdownHeight,
nothingFound: params.nothingFound,
placeholder: params.placeholder,
required: params.required,
searchValue: params.searchValue,
shadow: params.shadow,
size: params.size,
styles: params.styles,
switchDirectionOnFlip: params.switchDirectionOnFlip,
variant: params.variant,
})
)
);
// allow focus event
this.eInput.tabIndex = '0';
// set editor value to the value from the cell
this.value = params.value;
}
// gets called once when grid is ready to insert the element
getGui() {
return this.eInput;
}
focusChild() {
// needed to delay and allow the component to render
setTimeout(() => {
var inp = this.eInput.getElementsByClassName(
'mantine-Select-input'
)[0];
inp.tabIndex = '1';
// disable keyboard events while the cell editor is open
this.params.colDef.suppressKeyboardEvent = (params) => {
const gridShouldDoNothing = params.editing;
return gridShouldDoNothing;
};
// show dropdown options
inp.focus();
}, 100);
}
// focus and select can be done after the GUI is attached
afterGuiAttached() {
// store the active cell
this.prevFocus = document.activeElement;
// add event listener to trigger event to go into dash component
this.eInput.addEventListener('focus', this.focusChild());
// trigger focus event
this.eInput.focus();
}
// returns the new value after editing
getValue() {
return this.value;
}
// safely unmount the React component
destroy() {
// Delay the unmounting to avoid race conditions during render
setTimeout(() => {
if (this.root) {
// unmount the component and clean up
this.root.unmount();
this.root = null; // clear reference to avoid further operations
}
// set focus back to the grid's previously active cell
if (this.prevFocus) {
this.prevFocus.focus();
}
}, 0); // ensure unmount happens after rendering is complete
}
};
I then define the column with these two parameters:
"cellEditor": {"function": "DMC_Select"},
"cellEditorParams": {
"options": ["value1", "value2", "value3"],
"maxDropdownHeight": 280,
},
EDIT: i forgot the parameters are set for dmc.Select v12 so double check that!!!
EDIT: corrected:
dagfuncs.DMC_Select = class {
// gets called once before the renderer is used
init(params) {
// store the params
this.params = params;
// function for when Dash is trying to send props back to the component / server
var setProps = (props) => {
if (typeof props.value != typeof undefined) {
// updates the value of the editor
this.value = props.value;
// re-enables keyboard event
delete params.colDef.suppressKeyboardEvent;
// tells the grid to stop editing the cell
params.api.stopEditing();
// sets focus back to the grid's previously active cell
this.prevFocus.focus();
}
};
// create an element for the editor
this.eInput = document.createElement('div');
// create the root for rendering the React component
this.root = ReactDOM.createRoot(this.eInput);
// Get MantineProvider and Select from window
const MantineProvider = window.dash_mantine_components.MantineProvider;
const Select = window.dash_mantine_components.Select;
// Get global theme, styles, and other settings if available
const globalMantineConfig = {
theme: window.dash_mantine_components.mantineTheme || {},
styles: window.dash_mantine_components.mantineStyles || {},
colorScheme: window.dash_mantine_components.mantineColorScheme || 'light',
emotionCache: window.dash_mantine_components.mantineEmotionCache || null,
withGlobalStyles: true,
withNormalizeCSS: true,
};
// Render the Select component wrapped in the MantineProvider
this.root.render(
React.createElement(
MantineProvider,
globalMantineConfig,
React.createElement(Select, {
data: params.options,
value: params.value,
setProps,
style: {
position: 'fixed',
width: params.column.actualWidth - 2,
...params.style,
},
allowDeselect: params.allowDeselect,
checkIconPosition: params.checkIconPosition,
className: params.className,
classNames: params.classNames,
clearButtonProps: params.clearButtonProps,
clearable: params.clearable,
comboboxProps: params.comboboxProps,
darkHidden: params.darkHidden,
description: params.description,
descriptionProps: params.descriptionProps,
disabled: params.disabled,
dropdownOpened: params.dropdownOpened,
error: params.error,
errorProps: params.errorProps,
hiddenFrom: params.hiddenFrom,
hiddenInputProps: params.hiddenInputProps,
inputWrapperOrder: params.inputWrapperOrder,
label: params.label,
labelProps: params.labelProps,
leftSection: params.leftSection,
leftSectionPointerEvents: params.leftSectionPointerEvents,
leftSectionProps: params.leftSectionProps,
leftSectionWidth: params.leftSectionWidth,
lightHidden: params.lightHidden,
limit: params.limit,
loading_state: params.loading_state,
maxDropdownHeight: params.maxDropdownHeight,
mod: params.mod,
name: params.name,
nothingFoundMessage: params.nothingFoundMessage,
persisted_props: params.persisted_props,
persistence: params.persistence,
persistence_type: params.persistence_type,
placeholder: params.placeholder,
pointer: params.pointer,
radius: params.radius,
readOnly: params.readOnly,
required: params.required,
rightSection: params.rightSection,
rightSectionPointerEvents: params.rightSectionPointerEvents,
rightSectionProps: params.rightSectionProps,
rightSectionWidth: params.rightSectionWidth,
scrollAreaProps: params.scrollAreaProps,
searchValue: params.searchValue,
searchable: params.searchable,
selectFirstOptionOnChange: params.selectFirstOptionOnChange,
size: params.size,
styles: params.styles,
tabIndex: params.tabIndex,
variant: params.variant,
visibleFrom: params.visibleFrom,
withAsterisk: params.withAsterisk,
withCheckIcon: params.withCheckIcon,
withErrorStyles: params.withErrorStyles,
withScrollArea: params.withScrollArea,
wrapperProps: params.wrapperProps,
})
)
);
// allow focus event
this.eInput.tabIndex = '0';
// set editor value to the value from the cell
this.value = params.value;
}
// gets called once when grid is ready to insert the element
getGui() {
return this.eInput;
}
focusChild() {
// needed to delay and allow the component to render
setTimeout(() => {
var inp = this.eInput.getElementsByClassName(
'mantine-Select-input'
)[0];
inp.tabIndex = '1';
// disable keyboard events while the cell editor is open
this.params.colDef.suppressKeyboardEvent = (params) => {
const gridShouldDoNothing = params.editing;
return gridShouldDoNothing;
};
// show dropdown options
inp.focus();
}, 100);
}
// focus and select can be done after the GUI is attached
afterGuiAttached() {
// store the active cell
this.prevFocus = document.activeElement;
// add event listener to trigger event to go into dash component
this.eInput.addEventListener('focus', this.focusChild());
// trigger focus event
this.eInput.focus();
}
// returns the new value after editing
getValue() {
return this.value;
}
// safely unmount the React component
destroy() {
// Delay the unmounting to avoid race conditions during render
setTimeout(() => {
if (this.root) {
// unmount the component and clean up
this.root.unmount();
this.root = null; // clear reference to avoid further operations
}
// set focus back to the grid's previously active cell
if (this.prevFocus) {
this.prevFocus.focus();
}
}, 0); // ensure unmount happens after rendering is complete
}
};